C++三大特性之多态(二)---深度剖析各种虚继承虚函数以及虚表的内容存放
来源:互联网 发布:nginx 拦截指定域名 编辑:程序博客网 时间:2024/06/15 19:45
虚继承
(1).单继承
#include<iostream>using namespace std ;class B{public:virtual void Funtest1(){cout << "B::Funtest1()" << endl;}virtual void Funtest2(){cout << "B::Funtest2()" << endl;}public:int _data1;};class D:virtual public B{public:D(){}virtual void Funtest1(){cout << "D::Funtest1()" << endl;}virtual void Funtest3(){cout << "D::Funtest3()" << endl;}int _data2;};void test0(){D d1;d1._data1 = 2;d1._data2 = 3;cout << "sizeof(D)=" << sizeof(D) << endl;cout << "继承过来的基类的虚函数的虚表:"<<endl;B &b1 = d1;typedef void (*PVF)();PVF*pvf = (PVF*)*(int*)&b1;while (*pvf){(*pvf)(); //通过这个循环打印出虚表中存放的函数。pvf++;}cout << endl;pvf = (PVF*)*(int*)&d1;//对象的前四个字节存放一个指针,这个指针指向一个虚表,虚表中存放的都是函数入口地址。//这一句就相当于一个函数指针类型的指针去指向一个函数指针类型的数组。cout << "派生类自己新增的虚函数构成的虚表:"<<endl;while (*pvf){(*pvf)(); //通过这个循环打印出虚表中存放的函数。pvf++;}cout <<endl;}int main(){test0();system("pause");return 0;}
说明:从基类继承过来的虚表也是先拷贝一份基类的虚表,如果派生类中有虚函数重写,则用派生类中的虚函数代替基类中的虚函数,派生类中新增的虚函数构成一张虚表,如果派生类中没有新增虚函数,则不会有这张虚表,因此就不会有前四个字节去存放虚表的地址。如果派生类中既没有构造函数也没有析构函数,则不会有0x00000000这四个字节。简单的演示下这两种情况:
1)将派生类中新增的FunTest3()函数屏蔽,也即是派生类中没有新增的虚函数,再来看下内存:
2)将派生类中的构造函数屏蔽,放开刚刚屏蔽的FunTest3()函数。也就是派生类中既没有构造函数也没有析构函数,在来看下内存:
(2)多继承
注释:此代码中派生类中没有构造函数也没有析构函数,派生类中有自己新增的虚函数。
#include<iostream>using namespace std ;class C1{public:virtual void Funtest1(){cout << "C1::Funtest1()" << endl;}virtual void Funtest2(){cout << "C1::Funtest2()" <<endl;}public:int _data2;};class C2{public:virtual void Funtest3(){cout << "C2::Funtest1()" << endl;}virtual void Funtest4(){cout << "C2::Funtest3()" <<endl;}public:int _data3;};class D:virtual public C1,virtual public C2{public:virtual void Funtest4(){cout << "D::Funtest3()" << endl;}virtual void Funtest2(){cout << "D::Funtest2()" <<endl;}virtual void Funtest7() //派生类的虚函数。{cout << "D::Funtest7()" <<endl;}virtual void Funtest8() //派生类的虚函数。{cout << "D::Funtest8()" <<endl;}public:int _data4;};void test(){cout << "sizeof(D):" << sizeof(D) << endl; //sizeof(D):28 D d1;cout << "&d1" << &d1 <<endl; //看下派生类的地址。&d10051F98Cd1._data2 = 2;d1._data3 = 3;d1._data4 = 4;C1 &c1 = d1;cout << "&c1" << &c1 <<endl; //看下基类C1去引用一个派生类,基类的地址。&c10051F998typedef void (*PVF)();PVF *pvf = (PVF*)*(int*)&c1; //这就相当于一个二级指针指向一个指针数组。cout << "从C1继承过来的虚函数构成的虚表 :" << endl;while (*pvf){(*pvf)();pvf++;}cout << endl << endl;C2 &c2 = d1; //c2的地址就是d1偏移C1类型的地址。cout << "&c2" << &c2 <<endl; //看下基类C2去引用一个派生类,基类的地址。&c20051F9A0pvf = (PVF*)*(int*)&c2; //这就相当于一个二级指针指向一个指针数组。cout << "从C2继承过来的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout << endl;pvf = (PVF*)*(int*)&d1; //这就相当于一个二级指针指向一个指针数组。cout << "派生类自己的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout << endl;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}
说明:先拷贝基类的虚表,如果派生类中有虚函数重写,用重写的虚函数代替原来的虚函数,其他的不变,同样的如果派生类中有构造函数和析构函数之一或两者都有,则会多有四个字节存放0x00000000,如果派生类中没有新增虚函数,则不会有第一张虚表,因此也不会有前四个字节存放第一张虚表的地址。
(3)菱形继承
注释:此代码中派生类中没有构造函数也没有析构函数,派生类中有自己新增的虚函数。
#include<iostream>using namespace std ;class B{public:virtual void Funtest1(){cout << "B::Funtest1()" << endl;}public:int _data1;};class C1:virtual public B{public:virtual void Funtest1(){cout << "C1::Funtest1()" << endl;}virtual void Funtest2(){cout << "C1::Funtest2()" <<endl;}public:int _data2;};class C2:virtual public B{public:virtual void Funtest1(){cout << "C2::Funtest1()" << endl;}virtual void Funtest3(){cout << "C2::Funtest3()" <<endl;}public:int _data3;};class D:public C2,public C1{public:virtual void Funtest1(){cout << "D::Funtest1()" << endl;}virtual void Funtest3(){cout << "D::Funtest3()" << endl;}virtual void Funtest4(){cout << "D::Funtest4()" <<endl;}public:int _data4;};void test(){cout << "sizeof(D):" << sizeof(D) << endl; //sizeof(D):28 c1 12+c2 12+d 4 = 28D d1;d1._data1 = 1;d1._data2 = 2;d1._data3 = 3;d1._data4 = 4;C1 &c1 = d1;typedef void (*PVF)();PVF *pvf = (PVF*)*(int*)&c1; //这就相当于一个二级指针指向一个指针数组。cout << "从C1继承过来的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();pvf++;}cout << endl << endl;C2 &c2 = d1;pvf = (PVF*)*(int*)&c2; //这就相当于一个二级指针指向一个指针数组。cout << "从C2继承过来的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout << endl;B &b1 = d1;pvf = (PVF*)*(int*)&b1; //这就相当于一个二级指针指向一个指针数组。cout << "从基类B继承的虚函数构成的虚表:" << endl;while (*pvf){(*pvf)();*pvf++;}cout << endl;}int main(){test();cout << "hello..." <<endl;system("pause");return 0;}
0 0
- C++三大特性之多态(二)---深度剖析各种虚继承虚函数以及虚表的内容存放
- C++多态(二)虚表剖析以及菱形继承
- java的三大特性之多态
- java的三大特性之多态
- OC的三大特性之多态
- java的三大特性之多态
- 深入剖析C++继承,多态以及隐藏(二)。(纯虚函数以及重写与隐藏)
- 深入剖析C++继承,多态以及隐藏(二)。(纯虚函数以及重写与隐藏)
- 透过汇编另眼看世界之多继承下的虚函数函数调用(二)
- 三大特性之多态
- java三大特性:(二)继承
- 面向对象的三大特性之(二)继承
- 虚函数表的内存存放,多种继承关系下
- 虚函数表深度剖析
- 面向对象三大特性之多态(三)
- Objective-C基础学习笔记(五)-面向对象的三大特性之多态
- java面向对象的三大特性之多态
- 面向对象的三大特性之多态
- java 获取HttpRequest Header 的几种方法
- STL::set和mutiset用法浅析
- VI中的多行删除与复制以及一些基础用法
- 【转载】如何快速转载CSDN中的博客
- NOIP2011Mayan 游戏
- C++三大特性之多态(二)---深度剖析各种虚继承虚函数以及虚表的内容存放
- Java并发多线程面试题 Top 50
- 边框圆角
- 1677: [Usaco2005 Jan]Sumsets 求和
- Sparse Autoencoder学习笔记
- 一些面试题3.0
- NOIP2011计算系数
- 奇异值分解(SVD) --- 几何意义
- Android开发中高效的数据结构用SparseArray代替HashMap