【温故而知新】C++中类的大小与其继承关系
2023-09-27 14:29:20 时间
【本文参考微信公众号:“程序猿”,账号:imkuqin,原文链接】
1、空类:
//NullClass.h #pragma once class CNullClass查看CNullClass实例的大小:
int _tmain(int argc, _TCHAR* argv[]) CNullClass *pNullClass; pNullClass = new CNullClass; printf("size of CNullClass:%d\n",sizeof(*pNullClass)); delete pNullClass; return 0; }输出结果显示,CNullClass实例的大小为1,即空类的实例只占一个字节,且该字节的内容并无实质意义。
2、只包含方法成员的类
//SimpleClass.h #pragma once class CSimpleClass public: CSimpleClass(); ~CSimpleClass(); void memthod1(); //SimpleClass.cpp #include "stdafx.h" #include "SimpleClass.h"运行结果:
pSimpleClass = new CSimpleClass; printf("size of span style="font-family: Microsoft YaHei;" CSimpleClass /span :%d\n", sizeof(*pSimpleClass)); delete pSimpleClass; return 0; }
由此可知,一个类的成员函数并不影响类的实际大小。
3、包含数据成员的类
class COneMemberClass public: COneMemberClass(int data = 0) m_nData = data; m_nData2 = 0; ~COneMemberClass(){}; void foo(); void setData2(int data2); private: int m_nData; int m_nData2; void COneMemberClass::foo() printf("data: %d.\ndata2: %d.\n",m_nData,m_nData2); void COneMemberClass::setData2(int data2) m_nData2 = data2; int _tmain(int argc, _TCHAR* argv[]) COneMemberClass OneMemClass(1); OneMemClass.setData2(5); OneMemClass.foo(); printf("Size of COneMemberClass is %d.\n", sizeof(OneMemClass)); return 0; }运行结果:
内存结构如下:
可见,这种情况下,对象的保存内容为数据成员的值,按照声明中的顺序。
4、简单继承类:
class CSonClass : public COneMemberClass public: CSonClass(); ~CSonClass(); void foo(); private: int m_nSonData; CSonClass::CSonClass() m_nSonData = 3;
在内存中,首先存放的是基类的成员,然后是派生类的成员。如果派生类继续向下派生,则其子类的数据继续存放在后续地址中。
5、虚继承的类:
#include "OneMemberClass.h" class VirtualInheritClass : virtual public COneMemberClass private: int nData;运行结果:
内存结构:
可见,在虚继承的情况下,类的最前面多了8个字节的数据,这些字节中保存了一个指针变量,指向一个关于虚基类偏移量的数组,偏移量是关于虚基类数据成员的偏移量。
另外对于某一个类继承自多个父类(B和C),这些父类又虚拟继承自一个共同的父类(A)的情况,内存结构如:(偏移量指针)(B的数据成员)(偏移量指针)(C的数据成员)(本对象的数据成员)(基类A的数据成员)。虚拟继承利用虚基类偏移量表指针,使得即使某各类被重复继承,基类的成员也只存在一次。
6、带有虚函数的情况
第一种,一个空类中声明了一个虚函数:
class CVirtualNull public: CVirtualNull(); ~CVirtualNull(); virtual void foo(); CVirtualNull::CVirtualNull() printf("VirtualNull Class constructed.\n");
在这种情况下,CVirtualNull对象的大小为4,其内容只有一个指针,指向该类的虚函数表。第二种,某个子类继承了一个声明了虚函数的父类:
class CSubVirtualClass : public CVirtualNull public: CSubVirtualClass(); ~CSubVirtualClass(); private: int m_nubVirtualNull; CSubVirtualClass::CSubVirtualClass() m_nubVirtualNull = 5;
此时,CSubVirtualClass对象的大小为8字节。CSubVirtualClass类虽然没有直接声明虚函数,但是依然包含了基类的虚函数表(地址不同,指向内存的内容)。内存结构如下:
在单继承情况下,当子类自己定义了虚函数时,依然只有一个虚函数表(继承自父类),子类的虚函数指针将添加到这个虚函数表的后面。但当多继承时,子类中可能包含多个虚函数表,分别对应每一个父类。
第三种,包含虚函数类的虚继承
class VirtualInheritance private: int m_men1; public: virtual void aa(){}; class sonClass1 : public virtual VirtualInheritance private: int m_mem2; public: virtual void bb(){}; class sonClass2 : public virtual sonClass1 private: int m_mem3; public: virtual void cc(){}; };在 visual studio中的输出结果为:
对于VirtualInheritance类,其包含一个虚函数表+自身成员,大小为8。
对于sonClass1类,由于是虚拟继承因此包含一个虚函数偏移指针;由于自身存在虚函数,因此包含一个指向虚函数表指针;随后是自身的数据成员,最后是完整的父类对象。sonClass2情况与此类似。
总结:
1,普通单继承,只需将自身成员变量的大小加上父类大小(父类中 有虚函数,子类中不管有没有)若父类没有虚函数,则子类大小需要加上指向虚表的指针大小。
2,普通多继承,若几个父类都有虚表,则子类与第一个父类公用一个虚表指针,其他有几个有虚函数的父类则就有几个虚表指针。
3,虚拟单继承,此时若子类有虚函数则加上一个自身的虚表指针的大小,(若没有则不加)再加上自身的成员变量大小,还要加上一个虚类指针ptr_sonclass_fatherclass,最后加上父类的大小。
4,多重虚拟继承,此时若子类有虚函数则加上一个自身的虚表指针的大小,(若没有则不叫)再加上自身的成员变量大小,还要加上 一个公用的虚类指针(不管有几个虚拟父类,只加一个),在加上所有父类的大小。
5、普通、虚拟混合多继承,此时子类的大小为自身大小(若子类或普通父类有虚函数,则为成员变量+虚表指针大小;若都没虚函数,则就为成员变量大小),加上一个虚类指针大小,在加上虚拟父类的大小,在加上普通父类的大小(除虚表指针,因为它和子类公用一个虚表指针)。
一文真正学懂java接口 1.概述 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
jerry.yin 毕业于上海大学通信与信息工程学院,从事流媒体和视频编解码的研究与开发工作; 研究领域包括视频编解码标准、视频处理和流媒体技术、移动互联网技术等。
相关文章
- c++面试常用知识(sizeof计算类的大小,虚拟继承,重载,隐藏,覆盖)
- c++中继承和java中继承的对比
- 【C/C++开发】emplace_back() 和 push_back 的区别
- 【C/C++开发】运算符重载
- 【C++】继承/多态/文件
- C++反汇编第五讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式.
- C++│蓝桥杯省赛真题方格分割问题
- C++菱形继承以及解决方法--虚继承 虚基表
- 从零开始学C++之RTTI、dynamic_cast、typeid、类与类之间的关系uml
- 用C++ 设计一个不能被继承的类
- c++之继承与派生
- C++学习笔记_12 单向链表和单向链表模板 2021-04-29
- 百战c++(os1)
- C++ STL与迭代器
- 《挑战30天C++入门极限》图例实解:C++中类的继承特性
- 《挑战30天C++入门极限》图文例解C++类的多重继承与虚拟继承
- 《挑战30天C++入门极限》C++类的继承与多重继承的访问控制
- 高效C++规划
- C++继承模型
- 用C++实现一个不能被继承的类
- C++11中的原子操作(atomic operation)
- C++ | 继承关系与成员属性
- C++:再谈菱形继承问题 | 菱形继承时构造过程,内存模型是怎样的?
- C++:类的继承 | 补充基础问题 | 派生类的隐藏基类对象问题 | 切片现象
- C++:仿写STL的 list | 工业级代码 | 迭代器的仿写 | 功能单一的插入和删除函数所带来的便利
- C++ 类的继承与派生
- 初学C++,坚决不能挂!
- 可以继承的C++ Singleton基类