在学习《C++primer 第五版》(中文版)中第七章类的时候遇到了一个有意思的习题,原题如下:
- 练习7.43:假定有一个名为NoDefault的类,它有一个接受int的构造函数,但是没有默认的构造函数。定义类C,C有一个Nodefault类型成员,定义C的默认构造函数
本题的答案很简单,直接利用初始化列表给成员类提供一个默认参数即可,参考答案如下:
- struct Nodefault
- {
- private:
- int x;
- public:
- Nodefault(int y){};
- };
- struct C
- {
- private:
- Nodefault no;
- public:
- C() :no(1) {};
- };
但是当时想利用一个为所有参数都提供默认实参的构造函数来等价定义默认函数,于是将C的构造函数改为下式:
- C(Nodefault x= Nodefault(1)) :no(x) {};
初看这个构造函数的时候非常难以理解,本能的会将此行代码理解为:调用构造函数Nodefault(int)将其返回值当成x的默认初始值并利用列表初始化提供成员类no的初始值。这样理解有两个问题:
首先是构造函数是一个没有返回值的特殊函数,其次没有返回值的构造函数无法给"="提供一个有效的右值。
显然这样的理解是错误的,正确的执行流程应该是:
1、显式调用类Nodefault的构造函数Nodeafult(int),生成一个类的临时对象。
2、调用拷贝构造函数将临时对象拷贝给类C的成员类no(只调用一次拷贝构造函数)。
验证代码如下:
- struct Nodefault
- {
- private:
- int x;
- public:
- Nodefault(int y)
- {
- cout << "consttuction for Nodefault" << endl;
- };
- Nodefault(const Nodefault &c)
- {
- x = c.x;
- cout << "copy construction" << endl;
- }
- ~Nodefault() { cout << "deconstruction for Nodefault" <<endl; }
- };
- struct C
- {
- private:
- Nodefault no;
- public:
- C(Nodefault x= Nodefault(1)) :no(x){
- cout << "consttuction for C" << endl;
- };
- ~C() { cout << "deconstruction for C" << endl; }
- };
- int main()
- {
- C object;
- return 0;
- }
输出结果如下:
- 1 consttuction for Nodefault
- 2 copy construction
- 3 consttuction for C
- 4 deconstruction for Nodefault
- 5 deconstruction for C
- 6 deconstruction for Nodefault
注意:1、只调用一次拷贝构造函数,临时对象直接拷贝给成员类。
2、两次调用类Nodefault的析构函数:第一次在C对象构造函数结束时析构临时对象Nodefault、第二在程序结束时自动析构C后析构成员类Nodefaul