空类中都有哪些东西

定义一个空类,里面什么内容都没有

class A
{
};

想想看,它的大小应该是多少??

要计算一个类对象的大小,要知道这么几点:

  • 类大小是非静态数据成员的类型大小之和
  • 若类中定义了虚函数,需要考虑到虚表指针也占用类对象的内存空间(32位机器下占用四字节)
  • 编译器为了提高存取效率,类大小往往会被调整为系统的整数倍,和结构体中的内存对齐类似(结构体内存对齐详情戳这里为什么要进行结构体内存对齐)
  • 类大小与类的构造函数、析构函数和其他成员函数无关。

基于以上这些,理论上空类的大小应该是0,但是通过测试发现空类的大小为0。
C++标准规定类的大小不能为0,空类的大小为1,当类中不包含非静态成员变量和虚函数时,该类对象的大小也为1.

原因如下:
类的实例化是在内存中分配一块空间,每个对象在在内存中都有独一无二的地址,空类也能实例化,而空类实例化出的对象也需要一块独立空间,所以编译器会为空类隐含加一个字节,就能保证两个不同对象的地址不同。所以空类大小为1,而不是0.

空类中真的什么都没有吗??

并不见得,任何一个类中都有六个默认的成员函数,空类也不例外
六大默认成员函数分别是:

  • 构造函数
  • 拷贝构造函数
  • 析构函数
  • 赋值运算符重载
  • 取地址操作符重载
  • 被const修饰的取地址操作符重载

构造函数和析构函数在前面已经详细介绍过了,可以戳这里再温习一波构造函数和析构函数详解

在C++标准中,一个类中即使不显示给出以上这六个成员函数,编译器也会自动合成,但是由于不同的编译器都会有不同程度的优化,他们不一定在任何情况下都会合成这些成员函数,若对于一个构造函数,它既没有参数,在函数内部也不进行任何操作,合成也无任何意义,因此编译器就只会在需要的时候来合成。

以构造函数为例,编译器在那些情况下才会合成默认的构造函数??

有四种情况:
1.第一种
类A中有自己的默认构造函数,类B中没有,但是类B中包含了类A的对象,这种情况下,为了初始化B类中的A对象,编译器会为B类合成一个默认的构造函数。

2.第二种
若基类定义了构造函数,而派生类未定义构造函数,在创建派生类对象时,编译器会自动合成派生类的构造函数,目的是为了调用基类的构造函数。

这里顺便说一下继承体系下基类和派生类的构造函数/析构函数的调用次序
1.先调用派生类构造函数,再调基类构造函数;但是执行顺序相反,先执行基类的,再执行派生类的,即先构造基类的所有成员,再构造派生类成员。
2.析构函数是先调派生类的,再调基类的,后构造出来的先销毁,先销毁派生类成员,再销毁基类成员(相当于栈)。

3.第三种
在虚拟继承体系中,编译器为了将虚基表指针(基类成员变量偏移量表指针)放入派生类对象的前四个字节中,会合成构造函数。(虚拟继承了解一下)

4.第四种
若基类定义了虚函数,编译器会为其派生类合成构造函数,目的是将虚表指针放入派生类对象的前四个字节。(了解多态点这里)(深入学习就看这儿)


拷贝构造函数

是特殊的构造函数,创建对象时使用已存在的同类对象进行初始化编译器自动调用。

  • 函数名和类名相同
  • 参数为类对象的引用(一般用const修饰,防止修改原对象的值)

    为什么必须使用引用??
    试想一下,若此处的参数我们采用值传递,当传参时,形参是实参的一份临时拷贝,拷贝时也需要调用拷贝构造函数,所以它会一直递归调用,直到栈溢出

    • 若未显示定义,系统会自动合成默认拷贝构造函数,它会依次拷贝原对象的成员来初始化新对象。
何时会用到拷贝构造函数??
  • 用一个已存在类对象来实例化另一个同类对象
A a1;
A a2(a1);
  • 作为函数参数(传值方式)
void Fun(A a)
{}
  • 作为函数返回值(值返回方式)
A Fun()
{}

深拷贝和浅拷贝


赋值运算符重载

赋值运算符函数在定义时注意几点:
1.参数最好传引用(const修饰),可以少创建一个临时变量
2.返回值也返回引用,返回值的生命周期比函数要长
返回值不能为空,有可能还会连续赋值
3.一定要检查是否是自己给自己赋值,因为接下来的操作可能会释放空间,程序出错。

赋值运算符函数若未显示定义,系统会自动合成一个默认的赋值运算符函数,一般情况下都可以使用,但在有些情况下会出错,只要涉及资源,采用系统提供的就会有问题。
即所谓的深浅拷贝


取址运算符重载(&)

对该对象取地址,也就是this指针

类名* operator&()
{
    return this;
}

const修饰的取址运算符重载(&)

不能修改原对象
此时的this指针类型为 const 类名* const

const 类名* operator&()const
{
    return this;
}

你可能感兴趣的:(C++)