空类声明时不会生成任何默认成员函数

对于空类,编译器不会生成任何默认成员函数,只会生成1个字节的占位符。

有时可能会以为编译器会为空类生成默认构造函数等,事实上是不会的,编译器只会在需要的时候生成6个成员函数:一个缺省的构造函数、一个拷贝构造函数、一个析构函数、一个赋值运算符、一对取址运算符和一个this指针。所有这些只有当被需要才会产生。比如你定义了一个类,但从来定义过该类的对象,也没使用过该类型的函数参数,那么基本啥也不会产生。在比如你从来没有进行过该类型对象之间的赋值,那么operator=不会被产生。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
class Empty_one
{
};
class Empty_two
{};
class Empty_three
{
    virtual void fun() = 0;
};
class Empty_four :  public Empty_two, public Empty_three
{
};
int main()
{
  cout<<"sizeof(Empty_one):"<<sizeof(Empty_one)<<endl;	//1
  cout<<"sizeof(Empty_two):"<<sizeof(Empty_two)<<endl;	//1
  cout<<"sizeof(Empty_three):"<<sizeof(Empty_three)<<endl;	//4	
  cout<<"sizeof(Empty_four):"<<sizeof(Empty_four)<<endl;	//4
  return 0;
}

分析:

类Empty_one、Empty_two是空类,但空类同样可以被实例化,而每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址,所以sizeof(Empty_one)和sizeof(Empty_two)的大小为1。

类Empty_three里面因有一个纯虚函数,故有一个指向虚函数的指针(vptr),32位系统分配给指针的大小为4个字节,所以sizeof(Empty_three)的大小为4。

类Empty_four继承于Empty_two和Empty_three,编译器取消Empty_two的占位符,保留一虚函数表,故大小为4。

空类定义时可能会生成6个成员函数

当空类Empty_one定义一个对象时Empty_one pt;sizeof(pt)仍是为1,但编译器会生成6个成员函数:一个默认的构造函数、一个拷贝构造函数、一个析构函数、一个赋值运算符、两个取址运算符。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Empty  
{};  

class Empty  
{  
  public:  
    Empty();                            //默认构造函数  
    Empty(const Empty &rhs);            //拷贝构造函数  
    ~Empty();                           //析构函数   
    Empty& operator=(const Empty &rhs); //赋值运算符  
    Empty* operator&();                 //取址运算符  
    const Empty* operator&() const;     //取址运算符(const版本)  
};

使用时的调用情况:

1
2
3
4
5
6
7
Empty *e = new Empty();    //默认构造函数  
delete e;                  //析构函数  
Empty e1;                  //缺省构造函数                                 
Empty e2(e1);              //拷贝构造函数  
e2 = e1;                   //赋值运算符  
Empty *pe1 = &e1;          //取址运算符(非const)  
const Empty *pe2 = &e2;    //取址运算符(const)  

C++编译器对这些函数的实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
inline Empty::Empty()                          //缺省构造函数  
{  
}  
inline Empty::~Empty()                         //析构函数  
{  
}  
inline Empty *Empty::operator&()               //取址运算符(非const)  
{  
  return this;   
}             
inline const Empty *Empty::operator&() const    //取址运算符(const)  
{  
  return this;  
}  
inline Empty::Empty(const Empty &rhs)           //拷贝构造函数  
{  
  //对类的非静态数据成员进行以"成员为单位"逐一拷贝构造  
  //固定类型的对象拷贝构造是从源对象到目标对象的"逐位"拷贝  
}  
  
inline Empty& Empty::operator=(const Empty &rhs) //赋值运算符  
{  
  //对类的非静态数据成员进行以"成员为单位"逐一赋值  
  //固定类型的对象赋值是从源对象到目标对象的"逐位"赋值。  
}