深入理解多态

多态的概念

多肽在宏观上就是对某件事情的产生的多种行为;理论上多态就是多种形态。代码层面多态是重写函数的实现。

虚函数

在函数前面加上virtual就是虚函数了

 

虚函数的重写/覆盖的条件

1.两个虚函数分别位于基类和派生类的作用域

2.函数名/参数类型/返回值(协变除外)一样

3.两个都是虚函数

协变

协变是虚函数重写的一个特例,当两个虚函数的返回值是为任意父子关系的指针,此时也是虚函数重写。

9853c5a9581a454a8d05720366da272b.png

func函数就构成了协变

虚函数的接口继承(构成多态是有效)

当父类的函数是虚函数时,子类通过继承后,会将父类虚函数的声明继承下来。

4ea51ac4a4944c3180a6077e4c3f5bd1.png

如果形成多态,B中的就是

virtual void print(int val = 0)

 

 

 

形成多态的条件

1.完成虚函数的重写/覆盖

2.通过父类指针/父类的引用调用虚函数

为什么通过父类对象调用不行呢?

当我们用子类通过切片给父类时,虚函数表是不能拷贝给父类的,因为如果把虚函数表拷贝给父类后,当我们调用成员函数就无法确定调用的是父类的还是子类的。

 

多态在析构函数的运用

04c8fdce306f42c28123141ad4d30026.png

如图场景析构函数如果没有构成多态的话,析构行为就会发生错误

所以在继承里讲过析构函数会被编译器认为都是destrutor,将析构函数写成虚函数,这样的话在调用析构函数时就会构成多态,从而成功的析构。

 

纯虚函数

在函数末尾加上=0就是纯虚函数;

bcf0515f557c41da8e8b4529b5abb55f.png

抽象类

含有纯虚函数的类叫做抽象类。

抽象类不能实例化出对象,强制性要求子类重写虚函数,否则会编译报错。

抽象类可以有构造,拷贝构造,赋值重载,析构。

add06497a58e473aa6045d94b5e693e3.png

如图C就是抽象类,继承C的类必须对print进行重写,否在是无法实例化出对象。

 

 

多态的原理

在类中如果写了虚函数,则会生成一个虚函数指针数组来存放虚函数的地址,而类中则会有_vfptr指针指向这个虚函数指针数组。

单继承

314125c8d5704fc0bd96f4fa665757e9.png

多继承

61087e9d15ef48bd8a5e1fc767e3aa97.png

fd46eb5ac58b445fbef9fcc3e33089e7.png

323b86dc54f44752bc4f5571947c0e8e.png

C类继承了A类和B类后,对A的func1进行了重写,从上图可以看到重写后,C中A的func1变成C重写的;这样当我们用A*(指向C类对象的)指针调用func1,就是C重写的了,这样就实现了多态。

注意:

1.先继承的类在上面,上图先继承A,所以A就在上面

2.当我们在C类中写了A和B中都没有的虚函数时,虚函数会存储在优先继承的类的虚函数表内,可以通过内存查看,监视窗口看不到。

3.虚函数表指针时在对象调用构造函数时完成初始化的

4.虚函数表在编译期间就确定好了

5.虚函数表存在于代码段

如何查看虚函数

typedef void(*VFPTR) ();
void PrintVTable(VFPTR vTable[])
{
// 依次取虚表中的虚函数指针打印并调用。调用就可以看出存的是哪个函数
cout << " 虚表地址>" << vTable << endl;
for (int i = 0; vTable[i] != nullptr; ++i)
{
printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);
VFPTR f = vTable[i];
f();
cout << endl;
}
}

通过上面的接口就可以查看虚函数表内的虚函数了。

 

当A和B里面有相同的函数,C对这个函数进行了重写会怎么样呢?

88462adfabaf4f54a2ba19769b31c345.png

从上图我们可以发现A中的func1和B中的func1的地址不同,但是实际上A和B调用的是同一个func1,因为编译器对B进行了封装,那又为什么要封装呢,由于当我们用B*指针(指向的是C类中B这一部分)访问时this指针并不是指向C类的起始位置,所以要修正this指针的位置。

8837559f89ba410b86fed7f689c630bf.png

注意:当A和B都有相同的虚函数,C继承了A和B,C一定要对这个虚函数进行重写,不然编译器会报函数不明确的错误

菱形继承和多态

e8b3c8d68df245e3be21136ac35d0da0.png

 

 

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值