不考虑内部源码的话,创建一个空类 class A{},就会自动生成4个缺省的默认函数:默认构造、析构、拷贝构造、赋值运算符。且c++11引入右值引用和移动语义,还新增了移动构造函数和移动赋值函数。
//空类包含的默认函数
class A {
public:
A(); //默认构造
~A(); //析构
A(const A& obj); //拷贝构造
A& operator=(const A& obj); //拷贝赋值
//c++11以后
A(A &&); //移动构造
A& operator=(A &&); //移动赋值
};
对于空类的6个缺省函数的验证,把他们都调用一遍即可。
参考c++文档(CppReference.com):
如果没有为类类型(struct、class或union)提供任何类型的用户声明构造函数,编译器将始终将默认构造函数声明为其类的内联公共成员。
如果没有为类类型(struct、class或union)提供用户定义的复制构造函数,编译器将始终将复制构造函数声明为其类的非显式内联公共成员。
如果没有为类类型(struct、class或union)提供用户定义的复制赋值运算符,编译器将始终将其声明为该类的内联公共成员。
如果没有为类类型(struct,class或union)提供用户声明的预期(自C++20以来)析构函数,编译器将始终将析构函数声明为其类的内联公共成员。
如果没有为类类型(struct、class或union)提供用户定义的移动构造函数,并且以下所有内容均为true:
没有用户声明的复制构造函数;
没有用户声明的复制分配运算符;
没有用户声明的移动分配运算符;
没有用户声明的析构函数。
那么,编译器将声明一个移动构造函数作为其类的非显式内联公共成员,其签名为t::T(T&&)。
如果没有为类类型提供用户定义的移动赋值运算符,并且以下所有操作均为true:
没有用户声明的复制构造函数;
没有用户声明的移动构造函数;
没有用户声明的复制分配运算符;
没有用户声明的析构函数,
然后,编译器将声明移动赋值运算符为其类的内联公共成员,其签名为t&T::operator=(T&&)
强调一点,拷贝构造函数和赋值运算符函数的形参为常量引用 即 const A & ,好处是可以接受多种实参:
A 变量对象
A & 变量引用对象
const A 常量对象
const A & 常量引用对象
再强调一点构造和析构函数,编译器对于一个类对象的构造,会先检查类的所有函数,当无法找到匹配的构造函数 或 无法找到析构函数时,就不会构造这个对象。所以编译器能成功创建一个空类对象也即验证了:一个空类必有默认构造函数和析构函数
构造和析构都声明为private
构造声明为private
析构声明为private
有些文章说重载了取址和const取址的函数,但我觉得c++默认是不重载这俩的。
原因如下,正因为没有重载,所以&是无法取到可用地址的,仅相当于“A *p;”。