首先关于虚继承和普通继承的知识,我总结一下:

1.普通继承时,无论派生类是否定义新的虚函数,基类和派生类总是共享一个虚函数表,不需要另加指向虚函数的指针,派生类只是将虚函数表中的元素改成了派生类的地址而已,虚函数表还是一个,指针数量也没有增加。
2.虚继承时,若是派生类只是继承或重写基类中虚函数,则基类和派生类是共享一个虚函数表;若派生类新定义了虚函数,则需要新加一个虚指针指向新的虚函数表。

虚继承中还有一个虚基类指针的概念,我需要在子类中多维护一个指向基类的虚基类指针

普通继承

当单继承且普通继承时:每个含有虚函数的类只有一个虚函数表,所以只需要一个虚表指针即可;

当多继承且普通继承时:一个子类有几个父类则会有几个虚函数表,所以就有和父类个数相同的虚表指针来标识;

总之,普通继承时,不需要额外增加虚函数表指针。

虚继承

当虚继承时:无论是单虚继承还是多虚继承,需要有一个虚基类表来记录虚继承关系,所以此时子类需要多一个虚基类表指针;而且只需要一个即可。

当虚继承时可能出现一个类中持有多个虚函数表的情况:无论是单虚继承还是多虚继承,

如果子类没有构造函数和析构函数,且子类中的虚函数都是在父类中出现的虚函数,这个时候不需要增加任何虚表指针;只需要像多继承那个持有父类个数的虚表指针来标识即可;

如果子类中含有构造函数或者析构函数或二者都有,则在子类中只要每出现一个父类中的虚函数则需要增加一个虚函数表指针来标识此类的虚函数表;

例子:

class A
{
private:
int a;
public:
A() {}
~A() {}
void A1() {}
void A2() {}
virtual void V1() = 0;
virtual void V2() = 0;
};
class B
{
private:
int b;
public:
void B1() {}
virtual void V1() = 0;
void B2() {}
}; class AA
{
private:
char a[2];
public:
virtual void aa() {}
};
class CC : public virtual AA
{
private:
char b[2];
char a[2];
public:
virtual void bb() {}
virtual void aa() {}
}; int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(AA)<<endl;
cout<<sizeof(CC)<<endl;
return 0;
}

在32位的编译器下,A的大小是8,int值+一个虚函数指针,4+4=8。B的大小是8,同样是int值+一个虚函数指针,4+4=8。AA的大小是8,2个char+一个虚函数指针,并对齐,4+4=8。CC的大小是20,这里是虚继承,并且子类CC中有自己的虚函数,所以需要一个虚函数指针,再加上CC中的元素,4个char元素,刚好是4,再多一个虚基类指针,4,另外再加上基类的数据2个char数据,对齐到4,还有基类中A的虚函数指针,所以是20.

那么如果我把virtual去掉,就变成了普通继承,这个时候子类中不需要维护虚基类指针,而且,可以和基类AA共用一个虚函数表,只需要一个虚函数指针,再加上数据,一共是12。

所以我们可以发现,虚继承中,除非子类不增加新的虚函数,不然是要多增加一个虚函数指针的,即基类和子类不共享虚函数表了。

另外一个例子:

class A{
char k[3];
public:
virtual void aa(){};
};
class B:public virtual A{
char j[3];
public:
virtual void bb(){};
};
class C:public virtual B{
char i[3];
public:
virtual void cc(){};
};
int main()
{
cout << "sizeof(A):" << sizeof(A) << endl;
/*A:虚函数指针+k
B:B虚函数指针+k+A虚函数指针+j+虚基类指针
C:C虚函数指针+i+B虚函数指针+B虚基类指针+k+j+C虚基类指针+A虚函数指针*/
cout << "sizeof(B):" << sizeof(B) << endl;
cout << "sizeof(C):" << sizeof(C) << endl;
system("PAUSE");
return 0;
}

32位编译器下,输出依次是8,20,32。

关于虚继承的sizeof问题的更多相关文章

  1. 【整理】C++虚函数及其继承、虚继承类大小

    参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/deta ...

  2. 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

    #include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...

  3. sizeof运算符、虚函数、虚继承考点(待修改)

    参考: http://blog.csdn.net/wangyangkobe/article/details/5951248 下面的文章解释有错误,不要看.......... 记住几句话: 编译器为每个 ...

  4. C++对象模型:单继承,多继承,虚继承

    什么是对象模型 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程序设计的部分.对于各种支持的底层实现机制. 类中成员分类 数据成员分为静态和非静态,成员函数有静态非静态以及虚函数 clas ...

  5. C++中的虚继承 & 重载隐藏覆盖的讨论

    虚继承这个东西用的真不多.估计也就是面试的时候会用到吧.. 可以看这篇文章:<关于C++中的虚拟继承的一些总结> 虚拟基类是为解决多重继承而出现的. 如:类D继承自类B1.B2,而类B1. ...

  6. C++ 继承之虚继承与普通继承的内存分布

    仅供互相学习,请勿喷,有观点欢迎指出~ class A { virtual void aa(){}; }; class B : public virtual A { ]; //加入一个变量是为了看清楚 ...

  7. 虚继承之单继承的内存布局(VC在编译时会把vfptr放到类的头部,这和Delphi完全一致)

    C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼.虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内 ...

  8. 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响

    首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...

  9. C++_day8_ 多重继承、钻石继承和虚继承

    1.继承的复习 1.1 类型转换 编译器认为访问范围缩小是安全的. 1.2 子类的构造与析构 子类中对基类构造函数初始化只能写在初始化表里,不能写在函数体中. 阻断继承. 1.3 子类的拷贝构造与拷贝 ...

随机推荐

  1. pandas DataFrame的新增行列,修改、删除、筛选、判断元素以及转置操作

    1)指定行索引和列索引标签 index 属性可以指定 DataFrame 结构中的索引数组,  columns 属性可以指定包含列名称的行, 而使用 name 属性,通过对一个 DataFrame 实 ...

  2. 数据分析——Numpy/pandas

    NumPy NumPy是高性能科学计算和数据分析的基础包.部分功能如下: ndarray, 具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组. 用于对整组数据进行快速运算的标准数学函数(无需编 ...

  3. vue+element-ui:table表格中的slot 、formatter属性

    slot 插槽,table中表示该行内容以自定义方式展示 :formatter 方法,用来格式化内容 Function(row, column, cellValue, index) html < ...

  4. BeetleX大数据之产品分析服务

        数据规模过于庞大?数据标签过多难以管理?增加新的分析维度需要配置?这些beetlex.io都能轻松解决,即导即用,数据标签自动管理,轻易实现多种维度数据分析处理.接下介绍BeetleX针对产品 ...

  5. Android事件分发机制五:面试官你坐啊

    前言 很高兴遇见你~ 事件分发系列文章已经到最后一篇了,先来回顾一下前面四篇,也当个目录: Android事件分发机制一:事件是如何到达activity的? : 从window机制出发分析了事件分发的 ...

  6. java基础-01代理类

    简单的代理类实现案例主实现类:ProxyTestimport java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;im ...

  7.  打开APP  04 | 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型? 2020-02-26 何小锋

     打开APP  04 | 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型? 2020-02-26 何小锋

  8. SSL_ERROR_WANT_READ

    ``` 47757 2020/05/07 06:36:04 [debug] 19413#19413: *23421 event timer: 11, old: 15581551413, new: 15 ...

  9. UserControl和CustomControl两者区别

    UserControl 将多个WPF控件(例如:TextBox,TextBlock,Button)进行组合成一个可复用的控件组: 由XAML和Code Behind代码组成: 不支持样式/模板重写: ...

  10. sql多行合并

    例一 SELECT qqo.questionID '题目id', qqo.quesOption '选项' FROM qz_question_option qqo, qz_question qq WHE ...