Effective C++条款05:构造/析构/赋值运算之(了解C++默默编写并调用哪些函数)

一、C++类默认定义的函数

  • 如果class没有定义构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数,那么C++内部会动创建一个默认的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数。并且这些默认函数都是public且inline的

演示说明

 
  1. class Empty{}; //空类

  2.  
  3. Empty e1; //调用e1的默认构造函数

  4. Empty e2(e1);//调用e2的默认拷贝构造函数

  5. e2 = e1; //调用e2的默认拷贝赋值运算符

  6.  
  7. //程序结束

  8. //调用e1与e2的默认析构函数

二、默认构造函数、默认析构函数做了什么?

  • 默认构造函数与默认析构函数主要是给编译器一个地方用来防止“隐藏幕后”的代码,像是调用基类和非静态成员变量的构造函数和析构函数
  • 注意:编译器定义的默认析构函数是非virtual的,除非这个class的基类自身有virtual析构函数(这种情况下这个函数的虚属性(virtual)来自于基类)

三、默认拷贝构造函数、默认拷贝赋值运算符做了什么?

  • 默认拷贝构造函数/默认拷贝赋值运算符一样,都是在拷贝/对象赋值时将类的每一个非静态成员变量逐个拷贝到目标对象之中

拷贝构造示案例

 
  1. template<typename T>

  2. class NamedObject

  3. {

  4. public:

  5. //两个构造函数

  6. NamedObject(const char* name, const T& value);

  7. NamedObject(const std::string& name, const T& value);

  8.  
  9. private:

  10. std::string name;

  11. T objectValue;

  12. };

  13.  
  14. NamedObject<int> no1("dongshao", 2);

  15. NamedObject<int> no2(no1); //调用NamedObject<int>的默认拷贝构造函数

  • 上面的no2对象调用默认的拷贝构造函数来拷贝no1对象,其中的操作有:
    • 将no1对象的name数据成员拷贝给no2对象的name数据成员(又因为name为string类型,所以最终会调用string的拷贝构造函数来拷贝name)
    • 因为此程序中模板类型为int,所以objectValue为int内置类型,直接将no1对象的objectValue赋值给no2的objectValue
  • 对于赋值运算符来说,其与拷贝构造函数一样,也是逐个将数据成员进行重新赋值

拷贝赋值运算符的错误注意事项

  • 虽然拷贝构造函数与拷贝赋值运算符用起来比较类似,但是有一种情况会导致出错,见下面的演示案例
 
  1. template<typename T>

  2. class NamedObject

  3. {

  4. public:

  5. NamedObject(std::string& name, const T& value);

  6.  
  7. private:

  8. //此处将name改为了引用形式,objectValue改为了const类型

  9. std::string& name;

  10. const T objectValue;

  11. };

  12.  
  13.  
  14. std::string newDog("Persephone");

  15. std::string oldDog("Satch");

  16. NamedObject<int> p(newDog, 2);

  17. NamedObject<int> s(oldDog,36);

  18.  
  19. p = s; //错误

  • 上述“p=s”错误的原因:
    • name:因为name为引用类型了,我们知道引用一旦绑定就不可以改变引用指向,但是在此处拷贝赋值运算符中,我们将p的name引用从一开始指向于newDog又指向了oldDog,因此会发生错误
    • objectValue:因为objectValue为const类型,因此在初始化之后其值就不可以改变了,此处将p的值从2改变为36因此会发生错误

四、拒绝生成默认函数

  • 从“三”中的演示案例可以看到,在某些情况下,使用了系统提供的默认拷贝赋值运算符会出现错误。因此有些情况下我们不希望使用class提供的默认拷贝赋值运算符,那么就需要提供一种方法
  • 如果一个基类将拷贝赋值运算符声明为private,那么编译器就拒绝为派生类生成默认的拷贝赋值运算符。因为基类如果想使用这些函数,那么这些函数会相应的处理基类成份,但是基类是private的,所以不可以使用
  • 这种方法不仅适用于拷贝赋值运算符,对于构造函数、拷贝构造函数都同样有效

五、总结

编译器可以暗自为class创建默认构造函数、拷贝构造函数、拷贝赋值函数以及析构函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值