关闭

C++学习之多态的实现

241人阅读 评论(0) 收藏 举报
分类:

多态又分为静态多态和动态多态。

静态多态其实就是函数重载,动态多态就是一般我们所说的多态。

多态作为面向对象的三大特征之一,需要另外两大特征:封装、继承的支持。

本文主要讲讲,我看了一点《深度探索C++模型》总结多态是怎样实现的。

1.C++内存布局

C++对象主要可以有如下几种成员:

(1)数据成员

①static数据成员

②nonstatic数据成员

(2)函数成员

①static函数成员

②nonstatic函数成员

③virtual函数成员


其中,nonstatic数据成员和virtual函数成员是要占用,变量的内存空间的。

其他成员都是使用一个公共的静态区域。

具体地讲,每一个类对象会为其每一个nonstatic数据成员持有一个指针,而对于其所有的虚函数,会持有1个指针vptr,这个指针指向一个表vtbl,这个表里每一个位置也是一个指针,指向该类的各个虚函数。


2.多态的实现

在定义父类和子类的时候,父类对象的与子类对象都拥有vptr这个成员,但是父类的vptr指向的vtbl里面的指针指向的虚函数是父类的版本。

子类的vptr指向的btbl里面的指针指向的虚函数是子类的版本。

这个vptr指向的btbl里面放的虚函数是哪一个版本是由构造器、拷贝复制运算符决定的。

如果是构造一个父类对象,就是指向父类的虚函数,如果构造一个子类对象就是指向一个子类的虚函数。

如果把一个子类对象,强制转换为一个父类对象,其vptr也会变为指向父类虚函数的。


但是当我们把一个父类的指针赋值一个指向了子类的指针,这个时候首先会发生切割,将子类多出来的成员给切割掉。

因为不同类型的指针,会限定从该地址开始的后面的范围的内存布局。

但是由于指针赋值,并没有调用子类或者父类的构造器,并且vptr是子类对象与父类对象所共有的,所以并没有被切割。

所以这个时候如果一个指针开始指向了一个子类对象,现在通过这个指针调用的虚函数版本就是子类的,虽然这个指针现在是一个父类指针。


注意:

2016/06/01更新

我用G++ 4.9.2编译器验证出来的一些信息

1.vtbl源自父类的会不会也用来填装子类新加入的虚函数
会。
如果父类没有虚函数,子类有就会在子类额外区间多一个vptr
如果父类有虚函数,父类区间的vptr指向的vtbl也会存放子类新建的虚函数。


2.vtbl会不会同时用来记录虚基类信息
不会。有一个vptr,有一个vbtr
但是如果虚基类里面没有数据成员的话,是不会产生一个vbtr用于访问数据成员的。


3.如果是多重继承的虚拟基类是采用多少个vbtr
多重继承了多少个虚拟基类就会有多少个vbtr


4.如果是多阶继承
对于一阶,如果有单独定义的变量,那么每一阶就会产生一个vbtr


总结:
GCC的这些貌似少了很多优化,但是它好像是讲vptr和vbtr都用一个指针来实现的,然后进行了相应地处理。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:84648次
    • 积分:2816
    • 等级:
    • 排名:第13183名
    • 原创:203篇
    • 转载:13篇
    • 译文:0篇
    • 评论:8条
    最新评论