多态
前言
一个人,可以说他是只猴,也可以说他是哺乳动物,也可以说他是动物。但本质上就是个人。
正文
对象多态
在前言之中,人可以推导是动物,但是动物不能百分百推断为人。
- 向上转型 父类=>子类
- 向下转型 子类=>父类
1 | class animal{ |
可以看到这样转型编译器没有报错,但是实际上还是会发生内存切片的问题,毕竟子类继承之后多了属性,传给父类,就有一个地方无法表达。
编译器会给出提示。
内存切片,也就是我们此处,pople是有一个成员的,当由pople继承animal的类,然后实例化,那么其实已经有了三个成员,而animal本身就只有两个,所以用pople实例化的对象传给animal的时候那个多余的成员就很有可能会被抛弃掉。变量还能看得到,函数有的时候就不好说了。
像这样过不去的基本原因就是pople有三个成员内存多一块,而animal只有两块,所以不存在合适和构造函数去转换。
当然因为这种本身就不合理,比价合理的是通过指针或者引用去传值。
以前面的为例:
这样就不存在什么内存切片的问题了。
1 | animal anm{}; |
回到向下转型的问题,虽然强制转换anm为pople类型的指针,但是于本意上,更多的时候不会为了操作anm的内存而改变,可能是需要执行它的函数。
方法多态
静态多态
- 函数重载
- 函数模板
1 | void eat(animal &anm){ |
像这种写在外部的,依靠传入参数区分的就是我们的函数重载。
1 | template<typename T> |
像函数模板感觉还得在里面判断。
动态的像写在类中
1 | class animal{ |
当两个类不想关的时候,调用的eat就是各管各的。不用搞什么特殊。
可当继承的时候,函数也一并被继承,之前说过要么作用域要么using。
1 | class animal{ |
往函数里加形参固然是解决的问题之一,但从理解的角度则不是很好。
首先就是他是类的方法,本身就需要类去调用不说,你还要往里面传指针。
如果依照自上向下转型,制作一个基类的指针,然后if判断某个值,让这个指针指向派生类去做这个操作。
同样也是因为结果有了可变性不是固定死的,这种就被称为动态多态。
除了虚基类,还有虚函数
1 | class animal{ |
具体放后面讲
结语
next