[Effective C++ --005]了解C++默默编写并调用哪些函数
<前言>
编译器是个十分敬业的工作者,不但为你编译代码,甚至为你生成代码,不可思议吧。本文主要介绍编译器究竟会为我们生成和调用哪些代码。
<空类和非空类>
如果问什么样的类是空类?也许你会说下面的类就是空类。
class A{
};
好吧,我也是这么认为的。没有构造函数怎么创建对象?事实上编译器会自动地把A的定义转为下面这样的代码。
class A{
public:
A() { }
A(const A& rhs) { ... }
~A() { }
A& operator =(const A& rhs) { ... }
};
需要注意的是:只有这些函数被调用的时候,它们才会被创建出来。也就是当下面的代码存在时两者才是等同的。产生的析构函数是non-virtual。
A a0;           // 默认构造函数
                // 默认析构函数
A a1(a0);       // copy构造函数
a0 = a1;        // 赋值运算符
如果想禁止编译器自动生成这些函数该怎么办呢?答案是你自己显式的声明它们。
<各生成函数的介绍>
3.1.<构造函数和析构函数>
假如有一个关于Dog的类,包含Dog的Name和age信息。类的定义如下面的代码。
class Dog {
private:
    std::string name;
    int age;
public:
    Dog(const char* name, const int age);
    Dog(const std::string& name, const int age);
    ~Dog(){ }
};
这里声明了有参数的构造函数,所以编译器就不会为我们生成默认的构造函数了。析构函数的定义规则也是一样的。
下面介绍Copy构造函数和赋值运算符。
3.2.<Copy构造函数和赋值运算符>
    邻居家有两条狗:大黄1和大黄2,而且它们是双胞胎。
Dog bigYellow1("Big Yellow",3);
Dog bigYellow2(bigYellow);     // 调用Copy构造函数
    由编译器生成的Copy构造函数以bigYellow1.name和bigYellow1.age为初值来设定bigYellow2.name和bigYellow2.age。
两者之中,name的类型是string,幸运的是string类型有Copy构造函数,所以name属性的Copy是成功的。age的类型是int型,属于
基本数据类型,所以age的Copy是按字节Copy(Bitwise Copy)的,不需要Copy构造函数。
赋值运算符和Copy构造函数其行为基本上一致,但也是有区别的(传送门:http://www.cnblogs.com/whyandinside/archive/2012/05/12/2497237.html)。
那是不是编译器这种生成操作总能成功呢?答案当然是否定的。请看下面例子。
class Dog {
private:
    std::string& name;
    const int age;
public:
    Dog(const std::string& name, const int age);
    ~Dog(){ }
};
std::string name1("Big Yellow");
std::string name2("Big Yellow");
Dog bigYellow1(name1,); // 大黄1于去年归西了
Dog bigYellow2(name2,);
bigYellow1 = bigYellow2; // 大黄2取代了大黄1的位置
请注意与前一个例子的区别:Dog(const char* name, const int age);构造函数被删除了,age的类型被限定为const,name被声明为string的引用。
虽然name1和name2的内容都是“Big Yellow”,但存储的位置不同,也就是地址不同。那么进行赋值的时候会发生什么呢?
编译器试图把bigYellow2.name拷贝到bigYellow1.name字段中。因为name是引用类型,C++中并不允许让引用改指向不同对象,所以编译器对这样的赋值操作无可奈何。
对此,编译器就不会生成默认的赋值运算符,因此需要我们自己去实现。
面对age的赋值,编译器的反应也是一样的。因为更改const成员是不合法的。还有一种情况编译器也不会生成默认的赋值操作符。
当父类将赋值运算符声明为private,编译器将拒绝为其子类生成赋值运算符。因为无法调用子类都无权调用的成员函数。
■总结■
 1)编译器可以自动创建默认构造函数、析构函数、Copy构造函数和赋值运算符。
 2)如果不希望编译器这么做,需要显式定义它们。
 3)默认赋值运算符不能生成的3种情况:成员是引用型、const型或者父类的赋值运算符声明为private。
 4)GUI项目中基本上类的构造函数、析构函数都是显示声明的,Copy构造函数和赋值运算符目前没有发现有显式声明的。
[Effective C++ --005]了解C++默默编写并调用哪些函数的更多相关文章
- Effective C++ 之 Item 5:了解C++默默编写并调用哪些函数
		
Effective C++ chapter 2. 构造 / 析构 / 赋值运算 (Constructors, Destructors, and Assignment Operators) Item 5 ...
 - EC笔记,第二部分:5.了解C++默默编写并调用哪些函数
		
5.了解C++默默编写并调用哪些函数 1.C++空类 C++会为一个空类建立以下函数 (1).默认构造函数 (2).默认拷贝构造函数 (3).析构函数 (4).赋值运算符(如果成员包含引用类型或con ...
 - Effective C++ -----条款05:了解C++默默编写并调用哪些函数
		
面对“内含reference成员或者含const成员”的class内支持赋值操作,你必须自己定义copy assignment操作符. 如果某个base classes将copy assignment ...
 - effective c++(05)(06)之c++默默编写并调用的函数
		
1. 当只写一个空类的时候,编译器会为他声明一个copy构造函数,一个copy assignment函数和一个析构函数.如下: 如果写下: class Empty{ }; 编译器就会实现以下代码: c ...
 - Effective C++ 条款五  了解C++默默编写并调用哪些函数
		
//申明一个类时,编译器会默认为你提供四个函数. //无参构造函数,析构函数,copy构造函数,copy assignment操作符. template <typename T> ...
 - Effective C++条款05:了解C++默默编写并调用哪些函数
		
class Empty{}; class Empty{ Empty(){}; Empty(const Empty& rhs){}; ~Empty(){}; Empty& operato ...
 - 条款05:了解C++默默编写并调用哪些函数
		
每一个class都会有一个或多个构造函数.一个析构函数.一个copy assignment操作符.这些控制着基础操作,像是产出新对象并确保它被初始化.摆脱旧对象并确保它被适当清理.以及赋予对象新值. ...
 - 了解 C++ 默默编写并调用的函数
		
前言 对于一个类来说,最最基础的三类成员函数莫过于:构造函数,析构函数以及拷贝函数 (copy构造函数和=重载函数).即使你的类没有为这些函数做出定义,C++ 也会自动为你创建.本文将讲述的是 C++ ...
 - C++编译器默默编写并调用哪些函数
		
什么时候empty class(空类)不再是个empty class呢?当C++处理过它之后,是的,如果你自己没有声明,编译器就会为它声明(编译器版本)一个copy构造函数.一个copy assign ...
 
随机推荐
- RPi 2B UART作为调试口或者普通串口
			
/************************************************************************************** * RPi 2B UAR ...
 - 使用BusyBox制作嵌入式Linux根文件系统
			
STEP 1:构建目录结构 创建根文件系统目录,主要包括以下目录/dev /etc /lib /usr /var /proc /tmp /home /root /mnt /bin /sbin ...
 - windows 7环境下配置oracle 11g 客户端
			
首先要去官网上下载oracle 11客户端,(我用的是64位系统)地址: http://www.oracle.com/technetwork/database/features/instant-cli ...
 - Win32汇编环境配置
			
放假了,发现自己知识面窄,趁有时间就打算折腾下Win32汇编.其实在学校也上过汇编课,是基于dos的.那时老师不务正业,老跟我们讲政治经济文化,唯独不怎么讲课;再加上自己的问题,导致了dos汇编学得好 ...
 - POJ 2488  A Knight's Journey
			
题意:给一个n×m的棋盘,如果一个骑士可以从任意一个位置出发不重复的走遍棋盘的每个格子就输出字典序最短的路径. 解法:dfs.暴搜n×m次,只是被字典序输出坑了……而且字母是列序号数字是行序号……这两 ...
 - Kryo 为什么比 Hessian 快
			
Kryo 是一个快速高效的Java对象图形序列化框架,它原生支持java,且在java的序列化上甚至优于google著名的序列化框架protobuf.由于 protobuf需要编写Schema文件(. ...
 - UESTC 250 windy数(数位DP)
			
题意:题意:求区间[A,B]之间的,不含前导0,且相邻两数位之间相差至少为2的正整数有多少个. 分析:dp[i][j]表示,长度为i.以j为结尾的表示的个数,再加一个前导0判断即可 #include ...
 - java中equals和==的区别  (转)
			
java中equals和==的区别 值类型是存储在内存中的堆栈(以后简称栈),而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中. ==操作比较的是两个变量的值是否相等,对于引 ...
 - longblogV1.0——我的静态博客发布系统
			
longblogV1.0——我的静态博客发布系统 环境依赖: python3-markdown 作者:IT小小龙个人主页:http://long_python.gitcafe.com/电子邮箱:lon ...
 - jvm 漫谈 笔记
			
1.Jvm到底是什么呢? Jvm其实就是模拟一台计算机,每种cpu都有自己的指令集,jvm自己设置一套指令集,这就是我满看的的字节码,然后jvm需要执行这些字节码,其实这些字节码最终直接对应到cpu的 ...