【C++】简单介绍虚拟继承
2017-10-11 22:50
267 查看
一、虚拟继承的来源
类D继承自类C1和类C2,而C1类和C2类都继承自类B,类D中会两次继承B,为了节省空间,可以将C1、C2对B的继承定义为虚拟继承,而B就成了虚拟基类
二、虚拟继承与普通继承的区别
1.书写形式上:虚拟继承要加虚拟关键字virtual
2.对象模型区别:虚拟继承要多四个字节空间,多的四个字节为偏移量表格的地址
普通继承对象模型:基类部分在前-----派生类部分在后
虚拟继承对象模型:积累部分在最底下
3.对于继承成员的访问形式
普通继承:直接访问
虚拟继承:偏移量表格地址----->偏移量表格---->相对于基类的偏移量----->访问基类对象
4.构造函数不同
普通继承:
虚拟继承:(1)派生类---->合成构造函数---->将偏移量表格地址放对象前四个字节
(2)多一个参数--->1 (检测是否为虚拟继承)
三、虚拟继承的应用与形式
1.虚拟继承用来解决继承中的二义性
2.代码形式
(1)虚拟继承格式:
(2)菱形虚拟继承格式:
----------//菱形虚拟继承的对象模型
具体介绍见博客《菱形虚拟继承的对象模型分析》
四、类中某些成员的虚拟性
1.(1)构造函数、静态函数、友元函数都不能虚拟;
(2)析构函数可以虚拟但不建议写成虚拟形式,赋值运算符重载可以虚拟但不建议写成虚拟形式
2.各成员分析
(1)构造函数
不能虚拟; 创建对象时要调用构造函数,构造好后才可以查找虚表调用虚函数,当构造函数给成虚函数时就要从虚表中找构造函数,但不到构造函数无法生成虚表。
(2)静态函数
不能虚拟;静态函数不是成员函数,并且屏蔽了this指针,所以不能虚拟(注:只有成员函数才能给成虚拟函数)
(3)友元函数
不能虚拟;友元函数不是成员函数,所以不能虚拟
(4)析构函数
可以虚拟;但是析构函数给成虚拟函数后,析构函数的调用不明确,竟导致内存泄露,所以建议不要给成虚拟函数。
(5)运算符重载
可以虚拟;但是运算符重载给成虚拟函数后,派生类中的运算符重载虚函数与基类中的运算符重载虚函数构成重写,原本是想让对象调用各自类自己的运算符重载,然而有时对象会只调用某一个类中的运算符重载函数。所以不建议给成虚拟函数。
类D继承自类C1和类C2,而C1类和C2类都继承自类B,类D中会两次继承B,为了节省空间,可以将C1、C2对B的继承定义为虚拟继承,而B就成了虚拟基类
二、虚拟继承与普通继承的区别
1.书写形式上:虚拟继承要加虚拟关键字virtual
2.对象模型区别:虚拟继承要多四个字节空间,多的四个字节为偏移量表格的地址
普通继承对象模型:基类部分在前-----派生类部分在后
虚拟继承对象模型:积累部分在最底下
3.对于继承成员的访问形式
普通继承:直接访问
虚拟继承:偏移量表格地址----->偏移量表格---->相对于基类的偏移量----->访问基类对象
4.构造函数不同
普通继承:
虚拟继承:(1)派生类---->合成构造函数---->将偏移量表格地址放对象前四个字节
(2)多一个参数--->1 (检测是否为虚拟继承)
三、虚拟继承的应用与形式
1.虚拟继承用来解决继承中的二义性
2.代码形式
(1)虚拟继承格式:
class Base //基类 { public: int _b; }; class Derived :virtual public Base //虚拟继承 { public: int _d; }; int main() { cout << sizeof(Base) << endl; //4 cout << sizeof(Derived) << endl; //12 system("pause"); return 0; }
(2)菱形虚拟继承格式:
class B { public: virtual void Funtest1() { cout << "B::Funtest1()" << endl; } virtual void Funtest2() { cout << "B::Funtest2()" << endl; } public: int _b; }; class C1:virtual public B { public: virtual void Funtest1() { cout << "B::Funtest1()" << endl; } virtual void Funtest3() { cout << "C1::Fu 4000 ntest3()" << endl; } public: int _c1; }; class C2 :virtual public B { public: virtual void Funtest2() { cout << "B::Funtest2()" << endl; } virtual void Funtest4() { cout << "C2::Funtest4()" << endl; } public: int _c2; }; class D : public C1, public C2 { virtual void Funtest8() {} virtual void Funtest7() {} public: int _d; }; int main() { cout << sizeof(B) << endl; //8 cout << sizeof(C1) << endl; //20 cout << sizeof(C2) << endl; //20 cout << sizeof(D) << endl; //36 system("pause"); return 0; }
----------//菱形虚拟继承的对象模型
具体介绍见博客《菱形虚拟继承的对象模型分析》
四、类中某些成员的虚拟性
1.(1)构造函数、静态函数、友元函数都不能虚拟;
(2)析构函数可以虚拟但不建议写成虚拟形式,赋值运算符重载可以虚拟但不建议写成虚拟形式
2.各成员分析
(1)构造函数
不能虚拟; 创建对象时要调用构造函数,构造好后才可以查找虚表调用虚函数,当构造函数给成虚函数时就要从虚表中找构造函数,但不到构造函数无法生成虚表。
(2)静态函数
不能虚拟;静态函数不是成员函数,并且屏蔽了this指针,所以不能虚拟(注:只有成员函数才能给成虚拟函数)
(3)友元函数
不能虚拟;友元函数不是成员函数,所以不能虚拟
(4)析构函数
可以虚拟;但是析构函数给成虚拟函数后,析构函数的调用不明确,竟导致内存泄露,所以建议不要给成虚拟函数。
(5)运算符重载
可以虚拟;但是运算符重载给成虚拟函数后,派生类中的运算符重载虚函数与基类中的运算符重载虚函数构成重写,原本是想让对象调用各自类自己的运算符重载,然而有时对象会只调用某一个类中的运算符重载函数。所以不建议给成虚拟函数。
相关文章推荐
- C++ STL简单介绍
- C++中malloc和new的区别简单介绍
- C/C++程序员:排序算法之标准C语言qsort函数简单用法介绍
- C++复习(1):类的简单介绍及C语言中函数用法的扩充
- C及C++中typedef的简单使用介绍
- 简单介绍C/C++中结构体内存对齐
- C++模板的简单介绍
- [rapidjson]_[C/C++]_[rapidjson库使用简单介绍]
- c++ vector的简单介绍和使用
- C++中的string 类 简单介绍
- C/C++中关于结构(struct)和联合(union)的简单介绍
- C++ 预处理器的简单介绍
- c++ 指针、常量指针、指针常量、引用的简单介绍
- C++ 模板类 简单介绍
- C++ 堆与栈简单的介绍
- C++中各种排序简单介绍
- 各类经典搜索算法(Search Algorithms)的简单介绍和C++实现
- [rapidjson]_[C/C++]_[rapidjson库使用简单介绍]
- C++智能指针(一):智能指针的简单介绍
- C++中的string 类 简单介绍