[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,3); // 大黄1于去年归西了
Dog bigYellow2(name2,4);
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构造函数和赋值运算符目前没有发现有显式声明的。

时间: 2024-12-31 03:29:33

[005]了解C++默默编写并调用哪些函数的相关文章

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

Effective C++ chapter 2. 构造 / 析构 / 赋值运算 (Constructors, Destructors, and Assignment Operators) Item 5. 了解 C++ 默默编写并调用哪些函数 (Know what functions C++ silently writes and calls)

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

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验: 如果你自己没声明,编译器会自动声明copy constructor,copy assignment,destructor, 如果你没有声明任何构造函数,编译器会自动声明default constructor 示例: 如果你写下 class Empty{ }; 将会等价于 class Empty{ public: Empty() {...} //default构造函数 Empty(c

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

5.了解C++默默编写并调用哪些函数 1.C++空类 C++会为一个空类建立以下函数 (1).默认构造函数 (2).默认拷贝构造函数 (3).析构函数 (4).赋值运算符(如果成员包含引用类型或const类型,不会生成赋值运算符)(引用的对象和const对象不可更改,所以无法重新赋值) class cl1 { public: int a; cl1(int t):a(t) {}; }; class cl2 { public: int &a; cl2(int t):a(t) {} }; int ma

[effictive c++]条款05 了解c++默默编写并调用哪些函数

c++的编译器是非常智能的!当你声明一个空类empty class,如果你的代码有用到这个empty class时,编译器会默默的为你编写一些基本的函数.那么究竟编译器自己添加的函数都有哪些呢?构造函数,析构函数,一个copy构造函数和一个copy assignment操作符.举个例子来说明一下,如果你写下: class empty{}; 就好像你写下这样的代码: class Empty { public: Empty(){ ... } //default 构造函数 ~Empty(){ ....

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

在C++中,如果你写下 1 classEmpty{-}; 就相当于写下 1 classEmpty{ 2 public: 3 Empty();//default构造函数 4 Empty(constEmpty& rhs){--};//copy构造函数 5 ~Empty(){-}//析构函数 6 Empty&operator=(constEmpty& rhs){-};//copy赋值运算符 7 }; 惟有当这些函数被调用时,他们才会被编译器创建出来. 下面代码造成上述每个函数被创建: 1

第四篇:了解 C++ 默默编写并调用的函数

前言 对于一个类来说,最最基础的三类成员函数莫过于:构造函数,析构函数以及拷贝函数 (copy构造函数和=重载函数).即使你的类没有为这些函数做出定义,C++ 也会自动为你创建.本文将讲述的是 C++ “偷偷”为你创建的这三个函数究竟是怎么样的. 了解这些,能更清楚代码是如何运转的,从而写出自己需求的(这三类)函数,确保对象高效,节约. 默认的构造函数和析构函数 默认的构造函数/析构函数主要负责调用其基类的构造函数/析构函数. 默认的copy构造函数和=重载函数 默认的这两个函数仅仅是将对象的成

了解 C++ 默默编写并调用的函数

前言 对于一个类来说,最最基础的三类成员函数莫过于:构造函数,析构函数以及拷贝函数 (copy构造函数和=重载函数).即使你的类没有为这些函数做出定义,C++ 也会自动为你创建.本文将讲述的是 C++ “偷偷”为你创建的这三个函数究竟是怎么样的. 了解这些,能更清楚代码是如何运转的,从而写出自己需求的(这三类)函数,确保对象高效,节约. 默认的构造函数和析构函数 默认的构造函数/析构函数主要负责调用其基类的构造函数/析构函数. 默认的copy构造函数和=重载函数 默认的这两个函数仅仅是将对象的成

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

1. 成员函数只有被需要(被调用)才必须有定义,同理,只有当默认构造函数,拷贝构造函数,赋值操作符,析构函数被需要而类定义它们时,它们才会被编译器创建出来(除非函数在基类中被声明为虚函数,编译器产生的函数是非虚的,public的). 2. 并不是只要类没有定义默认构造函数,拷贝构造函数,赋值操作符时编译器就会自动合成它们,它们只有在"被需要"的时候才被产生. (具体见http://www.cnblogs.com/reasno/p/4742322.html) 3. 虽然编译器在类的创建者

C++编译器默默编写并调用哪些函数

什么时候empty class(空类)不再是个empty class呢?当C++处理过它之后,是的,如果你自己没有声明,编译器就会为它声明(编译器版本)一个copy构造函数.一个copy assignment操作符和一个析构函数.此外如果你没有声明任何构造函数,编译器也会为你声明一个default构造函数.所有这些都是public且inline. 编译器所生成的copy assignment操作符,其行为基本上与copy构造函数如出一辙,但一般而言只有当生出的代码合法且有适当机会证明它有意义,编