目录
sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。
sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。
使用 sizeof 的语法:sizeof (data type)
1、空类
空类指没有成员和函数的类,编译器为了区别不同的空类实例对象,为空类内部默认增加了一个字节地址用于区分。所以sizeof空类的大小为1个字节。
2、包含非静态成员变量类
类的大小是每个成员变量的占用内存的大小。 需要注意:有字节对齐规则:跟类中的成员变量类型最长的那个字节对对齐。 所以,为了节省空间,写类成员变量时,最小字节的写在前面。
关于字节对齐的介绍见链接
3、包含静态成员变量类
静态成员变量定义时就以及在全局/静态存储区分配了内存,不属于类对象。非其静态成员变量的内存是属于类对象的,每个类对象都会复制一份内存。 静态成员变量只有一份,生存周期属于整个程序,所以不占用内对象的空间,字节大小为1。
4、包含普通成员函数类
成员函数的不占用内存大小,大小和空类一样。
5、包含虚函数类
有虚函数的成员,类内部会有一个虚函数表指针vptr,vptr指向需函数表vtable,虚函数表中存放的是虚函数的地址。C++的虚函数机制跟C语言的函数指针(回调函数)类似。
虚函数表可参考链接:
C++继承和多态核心重点知识刨析,一文必拿下_c++继承与多态_小杰312的博客-优快云博客
C语言回调函数可参考链接:
C 函数指针与回调函数 | 菜鸟教程 (runoob.com)
6、继承虚函数类
只要基类有虚函数,子类不论实现或没实现,都有虚函数表。子类不会和父类共用一个虚函数表,每个类都会有一个虚函数表。
关于虚函数表可参考:
父类与子类会共用一个虚函数表吗?_父类和子类共用一个虚表_lann*的博客-优快云博客
c++ 子类没有虚函数,但是父类有虚函数,子类会新建虚表吗?_悠哉日常的博客-优快云博客
7、多重继承类
多重继承时,子类会继承两个基类的虚函数指针,分别指向虚函数表。子类与父类的同名函数,父类是虚函数,子类也是虚函数,子类的同名函数会覆盖父类的同名函数。
关于多重继承虚函数表可参考:
多重继承虚函数表分析_多层继承 虚函数表_Last-Week的博客-优快云博客
C++多态虚函数表详解(多重继承、多继承情况)_一个类有几个虚函数表_青城山小和尚的博客-优快云博客
8、虚函数表
虚函数表可参考:
demo代码如下:
#include <iostream>
using namespace std;
/*
* 1、空类
*/
class A
{
};
struct StuA
{
};
/*
* 2、类的非静态成员变量
*/
class B
{
public:
int m_a;
int m_b;
};
class B1
{
public:
long m_a;
char m_b;
int m_c;
char m_d;
};
class B2
{
public:
char m_a;
char m_b;
int m_c;
long m_d;
};
/*
* 3、静态成员变量
*
*/
class C
{
public:
static int m_a;
};
int C::m_a = 0;
/*
* 4、成员函数
*/
class D
{
public:
D(){};
~D(){};
void func(){};
};
/*
* 5、虚拟成员函数
*/
class E
{
public:
virtual void func(){};
};
/*
* 6、继承虚拟员函数
*/
class F
{
public:
virtual void func(){};
};
class F1:public F
{
public:
virtual void func(){};
};
/*
* 6、多重继承虚拟员函数
*/
class G
{
public:
virtual void func(){};
};
class G1
{
public:
virtual void func1(){};
};
class G2:public G,public G1
{
public:
virtual void func(){};
virtual void func1(){};
};
int main()
{
/*
* 1、编译器为了区别不同的空类实例对象,为空类内部默认增加了一个字节地址用于区分
*/
A objA;
StuA objA1;
cout << "sizeof A " << sizeof (objA) << std::endl; //output: 1
cout << "sizeof StuA " << sizeof (objA1) << std::endl; //output: 1
/*
* 2、类的非静态成员变量
* 类的大小是每个成员变量的占用内存的大小。
* 需要注意:有字节对齐规则:跟类中的成员变量类型最长的那个字节对对齐。
* 所以,为了节省空间,写类成员变量时,类型大小最小字节的写在前面,
* 或者最大类型字节的写在前面,只要按类型大小有序定义(降序/升序)就行!!!
*/
B b;
B1 b1;
B2 b2;
cout << "sizeof B " << sizeof (b) << std::endl; //output: 8
cout << "sizeof B1 " << sizeof (b1) << std::endl; //output: 24
cout << "sizeof B2 " << sizeof (b2) << std::endl; //output: 16
/*
* 3、静态成员变量
* 静态成员变量定义时就以及在全局/静态存储区分配了内存,不属于类对象。
* 非其静态成员变量的内存是属于类对象的,每个类对象都会复制一份内存。
* 静态成员变量只有一份,生存周期属于整个程序,所以不占用内对象的空间
*/
C c;
cout << "sizeof C " << sizeof (c) << std::endl; //output: 1
/*
* 4、成员函数
*/
D d;
cout << "sizeof D " << sizeof (d) << std::endl; //output: 1
/*
* 5、虚拟成员函数:虚函数表指针vptr指向需函数表vtable
*/
E e;
cout << "sizeof E " << sizeof (e) << std::endl; //output: 8
/*
* 6、继承虚拟成员函数
*/
F f;
F1 f1;
cout << "sizeof F " << sizeof (f) << std::endl; //output: 8
cout << "sizeof F1 " << sizeof (f1) << std::endl; //output: 8
/*
* 7、多重继承虚拟成员函数
* 继承两个虚函数表指针,不同的虚函数指针指向不同的虚函数
*/
G2 g2;
cout << "sizeof G2 " << sizeof (g2) << std::endl; //output: 16
return 0;
}
执行结果如下:
9、菱形继承
菱形继承的继承关系如下:
菱形继承存在数据冗余问题,如上面D类里面会包含两份A的数据成员。解决方法使用虚继承。虚拟继承是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。
使用虚继承的写法如下:
详细介绍可以参考博客:C++继承、多继承、菱形继承、虚继承 (万字) - HJfjfK - 博客园 (cnblogs.com)