飞道的博客

C++类内存分布,包含虚指针

196人阅读  评论(0)

首先类的内存空间大小,只与类中非静态的成员变量(int, char*)和虚函数指针个数有关,其中函数被存放到text区域,静态成员变量存放到.rodata区域,其实也就是数据区上面的只读存储区

顺便提一下,类的所有实例化对象共享类的虚函数表,虚函数表中存放的是虚函数的指针(也就是存放函数的地址),因此虚函数表的每一项都是sizeof(pointer)的大小(32位系统就是4B,64位就是8B)

当一个类中有虚函数时,类的内存中首先会存放虚函数表的指针,其次才会存放类中的非静态成员变量


  
  1. class Aarrt
  2. {
  3. int a = 1;
  4. int b = 2;
  5. virtual void vfunc() {
  6. }
  7. void print()
  8. {
  9. cout << 1 << endl;
  10. }
  11. };
  12. int main()
  13. {
  14. cout << sizeof(Aarrt) << endl;
  15. }

类的结构如下:

, 输出为12

当类Barrt继承了一个含有虚函数的Aarrt类的时候,Barrt会继承父类的虚函数表指针,并将其转为Barrt自己的虚函数表


  
  1. class Aarrt
  2. {
  3. int a = 1;
  4. int b = 2;
  5. virtual void vfunc() {
  6. }
  7. void print()
  8. {
  9. cout << 1 << endl;
  10. }
  11. };
  12. class Barrt : public Aarrt {
  13. int c = 3;
  14. virtual void vfuncB() {
  15. }
  16. };
  17. int main()
  18. {
  19. cout << sizeof(Barrt) << endl;
  20. }

,输出为16.并且可以看到Derive继承了父类的虚函数表指针,并指向了自己的虚函数表

 

而多重继承的时候,是会保留多份虚函数指针的


  
  1. class Base
  2. {
  3. int a;
  4. int b;
  5. public:
  6. void CommonFunction();
  7. void virtual VirtualFunction();
  8. };
  9. class DerivedClass1: public Base
  10. {
  11. int c;
  12. public:
  13. void DerivedCommonFunction();
  14. void virtual VirtualFunction();
  15. };
  16. class DerivedClass2 : public Base
  17. {
  18. int d;
  19. public:
  20. void DerivedCommonFunction();
  21. void virtual VirtualFunction();
  22. };
  23. class DerivedDerivedClass : public DerivedClass1, public DerivedClass2
  24. {
  25. int e;
  26. public:
  27. void DerivedDerivedCommonFunction();
  28. void virtual VirtualFunction();
  29. };

可以看到DerivedDerivedClass是同时保留了DerivedClass1和DerivedClass2的所有东西,因此就保存了两份虚函数表指针。这也就是为什么这种多重继承的时候有时候会导致冲突

因此引入了虚继承,虚继承就是使得多重继承的时候只保留一份公共的基类成员

然而具体实现是,每次虚继承的时候,子类单独保存父类的虚函数表指针,之后再新建一个自己的虚函数表指针。


  
  1. class Base
  2. {
  3. int a;
  4. int b;
  5. public:
  6. void CommonFunction();
  7. void virtual VirtualFunction();
  8. };
  9. class DerivedClass1 : virtual public Base
  10. {
  11. int c;
  12. public:
  13. void DerivedCommonFunction();
  14. void virtual VirtualFunction();
  15. };
  16. class DerivedClass2 : virtual public Base
  17. {
  18. int d;
  19. public:
  20. void DerivedCommonFunction();
  21. void virtual VirtualFunction();
  22. };
  23. class DerivedDerivedClass : public DerivedClass1, public DerivedClass2
  24. {
  25. int e;
  26. public:
  27. void DerivedDerivedCommonFunction();
  28. void virtual VirtualFunction();
  29. };
  30. int main() {
  31. cout << sizeof(DerivedDerivedClass) << endl;
  32. }

首先看DerivedClass1的类内存分布:

可以看到与public继承只保留一份基类虚函数表指针不同,子类自己创建了自己的虚函数表指针。DerivedClass2也是类似的

观看DerivedDerivedClass的内存分布为:

因为DerivedDerivedClass是public继承DerivedClass1 和2,因此是会和多继承一样继承DerivedClass1和DerivedClass2的虚函数表指针,同时只保留一份公共基类的虚函数表指针。

如果DerivedDerivedClass是virtual public继承DerivedClass1 和2,那么DerivedDerivedClass又会新建自己的虚函数表指针,同时保留父类的,其内存分布如下:

 

参考文献:

https://www.cnblogs.com/jerry19880126/p/3616999.html

https://blog.csdn.net/haoel/article/details/1948051  但这个文献中有一些错误,比如他说是每个对象维护一个虚函数表,但其实是每个对象维护一个公共的虚函数表指针等,但是主要汲取文章中继承时候虚函数表是如何修改的


转载:https://blog.csdn.net/mystyle_/article/details/116767988
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场