关于虚继承的sizeof问题
首先关于虚继承和普通继承的知识,我总结一下:
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问题的更多相关文章
- 【整理】C++虚函数及其继承、虚继承类大小
参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/deta ...
- 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte
#include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...
- sizeof运算符、虚函数、虚继承考点(待修改)
参考: http://blog.csdn.net/wangyangkobe/article/details/5951248 下面的文章解释有错误,不要看.......... 记住几句话: 编译器为每个 ...
- C++对象模型:单继承,多继承,虚继承
什么是对象模型 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程序设计的部分.对于各种支持的底层实现机制. 类中成员分类 数据成员分为静态和非静态,成员函数有静态非静态以及虚函数 clas ...
- C++中的虚继承 & 重载隐藏覆盖的讨论
虚继承这个东西用的真不多.估计也就是面试的时候会用到吧.. 可以看这篇文章:<关于C++中的虚拟继承的一些总结> 虚拟基类是为解决多重继承而出现的. 如:类D继承自类B1.B2,而类B1. ...
- C++ 继承之虚继承与普通继承的内存分布
仅供互相学习,请勿喷,有观点欢迎指出~ class A { virtual void aa(){}; }; class B : public virtual A { ]; //加入一个变量是为了看清楚 ...
- 虚继承之单继承的内存布局(VC在编译时会把vfptr放到类的头部,这和Delphi完全一致)
C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼.虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内 ...
- 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响
首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...
- C++_day8_ 多重继承、钻石继承和虚继承
1.继承的复习 1.1 类型转换 编译器认为访问范围缩小是安全的. 1.2 子类的构造与析构 子类中对基类构造函数初始化只能写在初始化表里,不能写在函数体中. 阻断继承. 1.3 子类的拷贝构造与拷贝 ...
随机推荐
- PKU2186 Popular Cows 受欢迎的牛
题目描述 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N(N<=10000)头牛,给你M(M<=50000)对整数(A,B),表示牛A认为牛B受欢迎.这种关系是具有传递性的,如果A认为B ...
- winform 添加背景图 闪屏问题解决
winform中只要添加了背景图片资源,窗体加载显示的时候就会出现不停的闪屏操作,网上找了很多方法,效果都不明显: 然后自己观察和思路:看窗体的加载过程,当有背景图的时候,首先出来的是背景图,之后背景 ...
- codeup 1934 查找元素
题目描述: 输入一个数n,然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标(从0开始,若不在数组中则输出-1. 输入: 测试数据有多组,输入n(1<=n<=200), ...
- Dapper原来还可以直接这样写SQL,很强大哦
网络上对Dapper的解释是这样的: Dapper是一个简单的.NET对象映射器,在速度方面具有"King of Micro ORM"的头衔,几乎与使用原始的ADO.NET数据读取 ...
- 让源码包apache服务被服务管理命令识别
在默认情况下,源码包服务是不能被系统的服务管理命令所识别和管理的,但是如果我们做一些设定,则也是可以让源码包服务被系统的服务管理命令所识别和管理的.不过笔者并不推荐大家这样做, 因为这会让本来区别很明 ...
- FastAPI实践项目:SayHello(FastAPI + vue.js + axios + element ui)
目录 简介 翻版 VS 本尊 后端服务 源码 接下来 简介 这次带来的是FastAPI + vue.js + axios + element ui (一个html文件里使用的) 实现的<Flas ...
- using-pointers-to-remove-item-from-singly-linked-list
https://stackoverflow.com/questions/12914917/using-pointers-to-remove-item-from-singly-linked-list
- gRPC Motivation and Design Principles | gRPC https://grpc.io/blog/principles/
gRPC Motivation and Design Principles | gRPC https://grpc.io/blog/principles/
- e.next = nil // avoid memory leaks e.prev = nil // avoid memory leaks
/Go/src/container/list/list.go:10
- 自动化接口差异测试-diffy 回归测试 charles rewrite 请求
https://mp.weixin.qq.com/s/vIxbtQtRRqgYCrDy7XTcrA 自动化接口差异测试-diffy Boris 搜狗测试 2018-08-30 自动化接口差异测试- ...