每一个class都会有一个或多个构造函数、一个析构函数、一个copy assignment操作符。这些控制着基础操作,像是产出新对象并确保它被初始化、摆脱旧对象并确保它被适当清理、以及赋予对象新值。

那么当你当你编写了一个empty class的时候,当你利用编译器的对代码进行处理的时候,它其实已经并非是一个empty  class 了。编译器会悄悄的给你生成了default 构造函数、一个析构函数、一个copy构造函数和一个copy assignment操作符,并且它们都是inline的(隐式inline)。如下代码示例

一个自定类: class empty{};

  其实等于以下代码:

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

  注意:上面的重载的操作运算符operator=的返回值是对象的引用,条款21似乎说了不要妄想返回对象的引用,这篇文章的意思不是说不能返回对象的引用,而是当你要返回对象的引用的时候,要确定引用的本体是谁,它能否被合理的delete

那么这四个名词的概念分别是:
default 构造函数:在你不提供任何构造函数的情况下,系统给出的一个不带参数,不包含函数代码的构造函数;但是当你声明了一个构造函数,编译器就不再为它创建default构造函数了。
析构函数:与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
copy构造函数:只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数成为构造函数(C++ pirmer定义)。经常被称作X(const X&),而且也是由编译自动调用。
 
copy assignment操作符:自动合成的一种赋值操作符。
 
什么时候会调用copy构造函数

以下三种情况出现时,会调用一个类的拷贝构造函数:
1) 用一个已经实例化了的该类对象,去实例化该类的另外一个对象;
2) 用该类的对象传值的方式作为一个函数的参数;
3) 一个函数返回值为该类的一个对象。
 
编译器在copy构造函数被需要(被调用),copy构造函数才会被编译器创建出来,但是注意,编译器产出的析构函数是个non-virtual,除非这个class的base class自身声明有virtual析构函数(这种情况下这个函数是虚属性)。
 
什么时候不会自动调用copy assignment操作符?
 
至于copy构造函数和copy assignment操作符,编译器创建的版本只是单纯地将来源对象的每一个non-static成员变量拷贝到目标对象。但在某些情况下编译器拒绝生成copy assignment操作符函数。比如存在引用成员和const成员。对于引用的改变,也就是说引用自身可被改动吗?如果是,那么就违背了C++的原则:引用不能修改指向对象。所以必须自己定义copy assignment操作符。但是对于copy构造函数,没有这方面的担心,因为对象里的引用或者const成员还没有被初始化。比如如下代码:
#include <iostream>  

using namespace std;  

class Person
{
public: Person(string& a, const int& b) : name(a), id(b) { } private: const int id;
string& name; }; int main()
{
Person p1(string("chu"), 1); Person p2(string("jun"), 2); p1 = p2;/////// error C2582: 'operator =' function is unavailable in 'Person' system("pause"); return 0;
}

  还有一种情况编译器不会生成copy assignment函数,就是基类将copy assignment声明为private,派生类型就无法获得编译器的帮助,因为编译器为derived classes所生成的copy assignment操作符要处理base class成分。因为派生类型无法调用基类型的copy assignment函数(不具备访问权限)。

#include <iostream>

using namespace std;

class BaseClass
{ private: BaseClass& operator=(const BaseClass& rhs) { } }; class derived : public BaseClass { }; int main()
{ BaseClass px1, px2; px1 = px2; ///// 'BaseClass::operator =' : cannot access private member declared in class 'BaseClass' system("pause");
return 0; }

  所以,请记住:

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

条款05:了解C++默默编写并调用哪些函数的更多相关文章

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

    面对“内含reference成员或者含const成员”的class内支持赋值操作,你必须自己定义copy assignment操作符. 如果某个base classes将copy assignment ...

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

    规则一 编译器默认操作 // 你认为 class Empty { }; // 实际上 class Empty { public: Empty() { ... } // default 构造函数 Emp ...

  3. Effective C++ 条款五 了解C++默默编写并调用哪些函数

      //申明一个类时,编译器会默认为你提供四个函数. //无参构造函数,析构函数,copy构造函数,copy assignment操作符.     template <typename T> ...

  4. EC笔记,第二部分:5.了解C++默默编写并调用哪些函数

    5.了解C++默默编写并调用哪些函数 1.C++空类 C++会为一个空类建立以下函数 (1).默认构造函数 (2).默认拷贝构造函数 (3).析构函数 (4).赋值运算符(如果成员包含引用类型或con ...

  5. Effective C++ 之 Item 5:了解C++默默编写并调用哪些函数

    Effective C++ chapter 2. 构造 / 析构 / 赋值运算 (Constructors, Destructors, and Assignment Operators) Item 5 ...

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

    class Empty{}; class Empty{ Empty(){}; Empty(const Empty& rhs){}; ~Empty(){}; Empty& operato ...

  7. effective c++(05)(06)之c++默默编写并调用的函数

    1. 当只写一个空类的时候,编译器会为他声明一个copy构造函数,一个copy assignment函数和一个析构函数.如下: 如果写下: class Empty{ }; 编译器就会实现以下代码: c ...

  8. 【05】了解C++默默编写并调用那些函数

    1.如果没有声明copy构造方法,copy赋值操作符,和析构方法,编译器会自动生成这些方法,且是inline. 2.如果没有声明任何构造方法,编译器会自动生成一个default构造方法,且是inlin ...

  9. 条款5.了解c++默默编写并且调用了哪些函数。

    如果想在一个内含reference成员的class内支持赋值操作,必须自己定义copy assignment操作符.而且面对“内含有const成员的”class,编译器的反应也是相同的,由于更改con ...

随机推荐

  1. 基于KVM建立虚拟机的步骤及总结说明

    1.前言 目前正在涉足云计算IaaS工作,虚拟化是IaaS的重要部分,因此这段时间对各个虚拟机化技术和工具进行研究,研究的目的不仅仅是为了会使用这个工具,而是通过研究了解技术的实现机制和原理,即知其然 ...

  2. Element DOM Tree jQuery plugin – Firebug like functionality | RockingCode

    Element DOM Tree jQuery plugin – Firebug like functionality | RockingCode Element DOM Tree jQuery pl ...

  3. Asp.net MVC中关于@Html标签的使用

    @Html帮助器简单说明,记录些基本的跟HTML中对应的@html帮助器,@Html基本包含了html中的表单控件和常用Html 在@Html中,带有For的主要是针对强类型的Html类型. 用于说明 ...

  4. HTML5API___manifest

    离线缓存 manifest 在html标签里面增加个属性 mainfest 就可以告诉浏览器缓存文件在哪里. <html manifest='show.manifest' xmlns=" ...

  5. Android乐学成语之自定义Adapter

    一.首先对Adapter概念深刻的了解 首先看看他的继承图

  6. 从零开始写驱动——vfd专用驱动芯片HT16514并行驱动程序编写

    前言 一直看别人搞的 vfd 很漂亮,前段时间淘了个 vfd 模块来,但没有模块资料,还好芯片没有打磨的,良心商家啊.周末抽空来研究一下这个东西. 从零开始 打开外壳 测试线路 查看芯片是 HT165 ...

  7. c++ primer plus 习题答案(8)

    p475.2 //头文件: class Cd{ private: char *performers; char *label; int selections; double playtime; pub ...

  8. 算法之旅,直奔<algorithm>之十五 find

    find(vs2010) 引言 这是我学习总结 <algorithm>的第十五篇.关于<algorithm>,每篇都很小,但是都很好用,可以秀出你的个性. 作用 find的作用 ...

  9. 在iOS上增加手势锁屏、解锁功能

    在iOS上增加手势锁屏.解锁功能 在一些涉及个人隐私的场景下,尤其是当移动设备包含太多私密信息时,为用户的安全考虑是有必要的. 桌面版的QQ在很多年前就考虑到用户离开电脑后隐私泄露的危险,提供了“离开 ...

  10. GraphLab:新的面向机器学习的并行框架

    大规模图数据计算引起了许多知名公司的关注,微软提出了用于图数据匹配的Horton - Querying Large Distributed Graphs(Link:http://research.mi ...