C++空类编译器自动生成的6个成员函数

一、问题

在C++中,编译器会为空类提供哪些默认成员函数?分别有什么样的功能呢?

二、详解

1、空类,声明时编译器不会生成任何成员函数

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

有时可能会以为编译器会为空类生成默认构造函数等,事实上是不会的,编译器只会在需要的时候生成6个成员函数:一个缺省的构造函数、一个拷贝构造函数、一个析构函数、一个赋值运算符、一对取址运算符和一个this指针。

代码:

[html] view plaincopy

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

运行结果:

分析:

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

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

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

2、空类,定义时会生成6个成员函数

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

[html] view plaincopy

  1. class Empty
  2. {};

等价于:

[html] view plaincopy

  1. class Empty
  2. {
  3. public:
  4. Empty();                            //缺省构造函数
  5. Empty(const Empty &rhs);            //拷贝构造函数
  6. ~Empty();                           //析构函数
  7. Empty& operator=(const Empty &rhs); //赋值运算符
  8. Empty* operator&();                 //取址运算符
  9. const Empty* operator&() const;     //取址运算符(const版本)
  10. };

使用时的调用情况:

[html] view plaincopy

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

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

[html] view plaincopy

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

例如:m是类C中的一个类型为T的非静态成员变量,若C没有声明拷贝构造函数(赋值运算符), m将会通过T的拷贝构造函数(赋值运算符)被拷贝构造(赋值);该规则递归应用到m的数据成员,直到找到一个拷贝构造函数(赋值运算符)或固定类型(例如:int、double、指针等)为止。

三、总结

(1)上述运行结果依赖于编译器和64位、32位不同的系统。

(2)本博文只是总结一些C++特性,也有无法理解的地方,不足之处还请指出,在此先感谢!

时间: 2024-08-11 18:37:39

C++空类编译器自动生成的6个成员函数的相关文章

C++空类编译器自动生成的6个成员函数、关于构造函数、拷贝构造函数的解释

对于空类,编译器不会生成任何的成员函数,只会生成1个字节的占位符. 有时可能会以为编译器会为空类生成默认构造函数等,事实上是不会的,编译器只会在需要的时候生成6个成员函数:默认构造函数.默认拷贝构造函数.默认析构函数.默认赋值运算符 这四个是我们通常大都知道的.但是除了这四个,还有两个,那就是取址运算符和 取址运算符 const. class Empty { public: Empty(); //缺省构造函数 Empty(const Empty &rhs); //拷贝构造函数 ~Empty();

C++如何拒绝编译器自动生成的函数

每一个class,编译器都会自动生成四个特殊成员函数: destructor(析构函数) default constructor(默认构造函数) copy constructor(copy构造函数) copy assignment operator =(copy assignment操作符) 但是有时候我们不想让我们设计的class有某些默认的构造函数.那么我们就应该明确禁止它. 比如我设计的一个class不想有copy构造函数和copy assignment操作符,那么我可以把这两个函数声明为

条款6:如果不想使用编译器自动生成的函数,就应该明确的拒绝。

有些情况自己是不希望生成拷贝构造函数以及拷贝赋值运算符的,这种时候不能只是自己不去编写这些函数,因为这样编译器会自动的去生成这些函数.保险一点的做法是将拷贝构造函数以及拷贝赋值运算符都声明为private的.这样既阻止了编译器生成默认的版本,而且又阻止了别人去调用它. 注意上面的这条“将成员函数声明为private而故意的不去实现它”是一种常用手段,即使是标准程序库中有的部分也是这样做的. class HomeForSale//很明显,销售的两个方子一般内容都是不相同的,所以拷贝构造函数以及 {

不使用编译器自动生成的拷贝构造函数和赋值运算符的方法

方法1:声明私有的拷贝构造函数和赋值运算符,这样不但阻止了编译器生成默认版本,并且使得用户无法调用他们,但是这时成员函数和友元函数还是可以调用他们,为了阻止他们的调用可以不定义这些私有的拷贝构造函数和赋值运算符.(标准库中也是如此阻止拷贝的) 代码段1.1:HomeForSale.h文件 #ifndef HOMEFORSALE_H #define HOMEFORSALE_H class CHomeForSale { public: CHomeForSale(){} private: CHomeF

【Effective c++】条款6:若不想使用编译器自动生成的函数就应该明确拒绝

地产中介卖的是房子,其使用的中介软件系统应该有个类用来描述卖掉的房子 class HomeFoeSale { ......} 但是任何房子都是独一无二的,不应该存在两个房子拥有同样的属性,因此以下操作不应该正确! HomeForSale h; HomeForSale h1(h); //调用复制构造函数 HomeForSale h2 = h; //调用赋值操作符 阻止这两个操作(复制.赋值)可以不声明它们,but自己不声明,编译器会自动生成,并且访问权限还是public.没办法只好声明出来,但是如

Effetive C++_笔记_条款06_若不想使用编译器自动生成的函数,就该明确拒绝

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 通常如果你不希望class支持某一特定机能,只要不声明对应函数就是了.但这个策略对copy构造函数和copy assignment操作符却不起作用,你如果不声明它们,而某些人尝试调用它,编译器会为你声明它们. 这把你逼到了一个困境.如果你不声明copy构造函数和copy assignment操作符,编译器可能为你产出一份,于是你的clas支持copying.如果

Effective C++ 条款六 若不想使用编译器自动生成的函数,就该明确拒绝

class HomeForSale //防止别人拷贝方法一:将相应的成员函数声明为private并且不予实现 { public: private: HomeForSale(const HomeForSale&); HomeForSale& operator = (const HomeForSale&);//只有申明,此函数很少被使用   };   //方法二,设计一个专门用来阻止copying动作的基类,然后让其他类继承这个类即可   class Uncopyable { prot

条款6:若不想使用编译器自动生成的函数,就该明确拒绝

如果自己定义的类中并不需要copy assignment操作符或者copy构造函数,为了避免编译器自动生成 因为编译器自动生成的没什么用,一般是按照顺序进行赋值或者拷贝,对于有对象内含有指针的话可能会出现一些问题 可以在private中声明(并不定义)它们.但是,友元和成员函数依然可以调用它们. 在C++11标准中可以用如下方法: class A { public: A(const A&) = delete;//不实现的函数可以不用写参数,光是声明其实也可以不用写参数 A operator=(c

effective c++ 条款06:若不想使用编译器自动生成的函数,就该明确拒绝

记住:为防止编译器暗自提供的功能,可将相应的成员函数声明为privae并且不予实现.也可以使用Uncopyable这样的父类实现. 对于独一无二的对象,希望不支持拷贝构造函数和赋值操作符. class HomeForSale { public: ... private: HomeForSale(const HomeForSale&); //只是声明,阻止编译器自动生成 HomeForSale& operator=(const HomeForSale&); } HomeForSale