Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls)

  • 条款05:了解C++默默编写并调用哪些函数
    • 编译器为类生成的默认函数做了什么?
  • 总结

《Effective C++》是一本轻薄短小的高密度的“专家经验积累”。本系列就是对Effective C++进行通读:


条款05:了解C++默默编写并调用哪些函数

  什么时候 empty class(空类)不再是个空类呢?

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

示例:
  如果你写下一个空类:

class Empty{}; //空类

  这就好比,你写下了:

class Empty{public:Empty() { ... }  //default构造函数Empty(const Empty& rhs) { ... } //Copy构造函数~Empty() { ... } //析构函数Empty& operator={const Empty& rhs) { ... } //copy assignment操作符
};

  只有当这些函数被需要(被调用),它们才会被编译创建。

class Empty{}; //空类Empty e1;    //调用e1的默认构造函数
Empty e2(e1);//调用e2的默认拷贝构造函数
e2 = e1;     //调用e2的默认拷贝赋值运算符//程序结束
//调用e1与e2的默认析构函数

编译器为类生成的默认函数做了什么?

现在知道编译器为你写了函数,那么这些函数做了什么呢?

默认构造函数与默认析构函数

  默认构造函数与默认析构函数主要是给编译器一个地方用来防止“隐藏幕后”的代码,像是调用基类和非静态成员变量的构造函数和析构函数

注意:编译器定义的默认析构函数是非virtual的,除非这个class的基类自身有virtual析构函数(这种情况下这个函数的虚属性(virtual)来自于基类)

默认拷贝构造函数和默认拷贝赋值运算符

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

示例:

template<typename T>
class NamedObject
{public:NamedObject(const char* name, const T& value);NamedObject(const std::string& name, const T& value);...
private:std::string name;T objectValue;
};

  这里声明了一个构造函数,所以编译器不再为它创建默认构造函数。而NamedObject即没有声明拷贝构造函数,也没有声明拷贝赋值运算符,所以编译器会生成默认的。下面是拷贝构造函数的用法:

NamedObject<int> no1("dongshao", 2);
NamedObject<int> no2(no1);  //调用NamedObject<int>的默认拷贝构造函数

上面的no2对象调用默认的拷贝构造函数来拷贝no1对象,其中的操作有:

  将no1对象的name数据成员拷贝给no对象的name数据成员(又因为name为string类型,所以最终会调用string的拷贝构造函数来拷贝name)

  因为此程序中模板类型为int,所以objectValue为int内置类型,直接将no1对象的objectValue赋值给no2的objectValue

  对于赋值运算符来说,其与拷贝构造函数一样,也是逐个将数据成员进行重新赋值。

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

  虽然拷贝构造函数与拷贝赋值运算符用起来比较类似,但是有一种情况会导致出错,如:

template<typename T>
class NamedObject
{public://以下构造函数不再接受一个 const 名称,因为 nameValue//因为name变为了string引用类型,因此参数1位char*类型的构造函数就没有用了NamedObject(std::string& name, const T& value);...        //假设并未声明 operator=
private:std::string& name;  //string的引用类型const T objectValue; // const
};std::string newDog("Persephone");
std::string oldDog("Satch");
NamedObject<int> p(newDog, 2);
NamedObject<int> s(oldDog,36);p = s; //错误

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

  objectValue:因为objectValue为const类型,因此在初始化之后其值就不可以改变了,此处将p的值从2改变为36因此会发生错误。

面对这个难题,C++ 的响应是拒绝编译那一行赋值动作。如果你打算在一个"内含引用成员"的 class 内支持赋值操作,你必须定义自己的拷贝赋值操作符。

  在某些情况下,使用了系统提供的默认拷贝赋值运算符会出现错误。因此有些情况下我们不希望使用class提供的默认拷贝赋值运算符,那么就需要提供一种方法:

  如果一个基类将拷贝赋值运算符声明为private,那么编译器就拒绝为派生类生成默认的拷贝赋值运算符。因为基类如果想使用这些函数,那么这些函数会相应的处理基类成份,但是基类是private的,所以不可以使用。

这种方法不仅适用于拷贝赋值运算符,对于构造函数、拷贝构造函数都同样有效

NOTE:

编译器可以暗自为class创建 default 构造、 copy 构造、copy 赋值操作符,以及析构函数。

总结

期待大家和我交流,留言或者私信,一起学习,一起进步!

Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls)相关推荐

  1. Effective C++:条款05:了解C++默默编写并调用哪些函数 (Know what functions C++ silently writes and calls.)...

    编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数. 转载于:https://www.cnblogs.com/elite/arc ...

  2. EffectiveC++详解:条款05-了解C++默默编写并调用哪些函数

    文章目录 条款05-了解C++默默编写并调用哪些函数 当我们写了一个空类,意味着什么 编译器什么时候拒绝生成拷贝赋值运算符 总结 @Author:CSU张扬 @Email:csuzhangyang@g ...

  3. Effective C++ 学习笔记 条款05 了解C++默默编写并调用了哪些函数

    当写下一个空类时,编译器会为你合成一个拷贝构造函数.一个拷贝赋值运算符.一个析构函数,如没有声明其他的构造函数,编译器会合成一个默认构造函数.这些都是inline的public成员. 当类有一个引用成 ...

  4. [Effective C++读书笔记]005_条款05_了解C++默默编写并调用哪些函数

    其实这一点在C++的基础类入门书,如C++ primer里面也有说过,不过很少有人去注意而已,作者把这一点提出来,是为了提醒我们. 这一条款的内容如下:就是说当你书写下面的[代码片段1]的时候,其实经 ...

  5. Effective C++记录(5):Know what functions C++ silently writes and calls.

    了解C++默默编写并调用的哪些函数 1. 空类:默认构造函数.拷贝构造函数.析构函数.拷贝赋值操作符. 注意: a. 声明构造函数后,编译器将不再为该类常见默认构造函数. b. 当内含referenc ...

  6. 了解C++默默编写并调用哪些函数

    在C++中,如果你写下 1 classEmpty{-}; 就相当于写下 1 classEmpty{ 2 public: 3 Empty();//default构造函数 4 Empty(constEmp ...

  7. Effective C++条款05:了解C++默默编写并调用哪些函数

    class Empty{};class Empty{Empty(){};Empty(const Empty& rhs){};~Empty(){};Empty& operator=(co ...

  8. 条款05:了解C++默默编写并调用哪些函数

    空类 如果你没有声明,编译器会为它声明一个default构造函数,copy构造函数,析构函数,赋值操作符. class Empty{}; //--------- class Empty { publi ...

  9. 条款5:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls)...

    1.default costructor  / copy constructor / copy assignment 者三者的区别? 特别是copy constructor & copy as ...

最新文章

  1. 重磅!我国建成首个自动驾驶封闭高速公路测试环境
  2. 智能车竞赛:提问与回答
  3. wprintf 和 wcout
  4. linux关于/etc/profile.d与/etc/profile的正确运用
  5. Linux学习-15-学习LVM逻辑卷
  6. c# 批量mqtt_Paho-MQTT C#接入示例
  7. RHEL5中实现各种服务的准备条件:
  8. Android局域网工具,NetX(局域网管理工具)
  9. Linux——虚拟机系统安装
  10. Idea中常用的快捷键(持续更新)
  11. 2022年信息安全工程师考试知识点:信息安全管理基础
  12. SiamRPN++详解:论文翻译
  13. 举个栗子!Tableau 技巧(131):用烛台图 Candlestick Chart 分析价格波动
  14. 白话机器学习-Encoder-Decoder框架
  15. 微擎服务器数据迁移 ,微擎通过迁移数据方式搬家换服务器换站点换域名【图文教程】
  16. 爬取起点小说总排行榜
  17. Android基础与手机历史
  18. Zeppelin打开定时调度
  19. VC++6.0英文原版+MSDN6.0下载(ISO格式)
  20. Feinstein Institute研究人员解码脑沟和白质区域的神经活动,预测手指运动和手部触觉刺激...

热门文章

  1. Linux命令_Note1
  2. 2020年8月20计算机大赛,NOI2020于8月17日正式开幕!今年哪些竞赛选手被保送清北计算机专业?...
  3. xgboost2 以及使用XGB.CV来进行调参
  4. 可变变量和不可变变量
  5. 【java】 【接口】【继承】【抽象类】案例 运动员和教练
  6. Spellchecker inspection helps locate typos and misspelling in your
  7. 小学生10以内加减运算练习系统(c语言)
  8. ModuleNotFoundError: No module named ‘xxx‘; ‘xxx‘ is not a package解决
  9. 我入门 Python 后总结的基础教程
  10. 西克推出LBR/LFR长距离非接触物位/液位传感器