隐式创建默认构造函数的迷惑(一)

隐式创建默认构造函数的迷惑(一)

《深度探索C++对象模型》读书笔记

飘飘白云

《深度探索C++对象模型》(以后简称《深探》)书中如此给新手提醒:

C++新手一般有两个常见的误解:


1, 任何 class 如果没有定义 default constructor ,就会被合成出一个。


2, 编译器合成出来的 default constructor 会明确设定 class 内每一个 data member 的默认值”。


如你所见,没有一个是真的!”。

看了这一段,是不是觉得大学里教C++的就是糊弄小朋友的,如果不是见到这段话,我还会傻乎乎地相信,每个类如果没有定义默认构造函数,就会自动创建一个,并使用“零值”初始化数据成员。

先看个例子:

#include <iostream>


using namespace std;



class Foo


{


public :


int val;



// Foo()


// {


// };


virtual ~Foo()


{


};



protected :


private :


};



int main()


{


Foo bar ;


if ( bar.val == 0)


{


cout << "Data member val has been initialized to 0" << endl;


}


else


{


cout << "Data member val hasn't been initialized to 0" << endl;


}


}

VS下编译运行输出:Data member val hasn't been initialized to 0 如果把被屏蔽的那个空构造函数恢复,输出结果就是另外一回事了。

那么到底在什么情况下,C++编译器会为我们创建默认构造函数,并初始化数据成员呢?C++ StandardISO-C++95〕里面这么说的:

“对于 class X ,如果没有任何用户声明的构造函数,那么会有一个默认构造函数被隐式声明出来…… 一个被隐式声明出来的默认构造函数将是一个没什么用的(trival)构造函数。”

这里所说的“没什么用的(trival)”是指仅仅是为了编译器编译的需要,而不是为了程序需要(比如变量必须初始化)而创建这么一个构造函数。看了上面这段话,感觉前面的提醒似乎有点不对,呵呵,后面还有说明:

在四种情形下,“编译器必须为未声明constructorclasses 合成一个 default constructor”,C++标准把那些合成物成为 隐式的有用的(nontrivaldefault constructor,它们只能满足编译器的需要。


在这四种情况之外而有没有声明任何 constructor classes ,拥有的是隐式的没什么用的( trivial default constructor ,实际上它们并不会被合成出来。

下面我们依次来说明这四种情形A,B,CD<待续>

情形A:拥有成员对象,并且这个成员对象所属的类拥有默认构造函数。

一个类没有任何构造函数,但是它内含有一个成员对象,而这个成员对象有默认构造函数,那么编译器就会在必要的时候为这个类隐式合成一个有用的(nontrival)构造函数。

还是来看代码说的清楚些:



#include
<iostream>


using namespace std;


class Foo


{


public :


// Foo()


// {


// cout << "Default constructor of Foo!";


// };



Foo(int a){


iFooVal = a;


cout << "Common constructor of Foo!";


};


~Foo(){



};


int iFooVal;


};



class Bar


{


public :


Foo foo;


int iBarVal;


~Bar()


{


};


};



int main()


{


Bar bar;



if (bar.foo.iFooVal == 0)


{


cout << "Member data of foo has been initialized!"<< endl;


}



if (bar.iBarVal == 0)


{


cout << "Member data of bar has been initialized!" << endl;


}



}

在这段代码里,我把成员对象Foo的默认构造函数屏蔽了,按照上面的解释,应该是会报错,因为类Bar不会合成一个隐式的有用的默认构造函数。编译运行,看看编译器怎么说:

error C2512: 'Bar' : no appropriate default constructor available

呵呵,不出所料!如果我们恢复Foo的默认构造函数Foo(),则编译运行输出:

Default constructor of Foo!

注意:BarFoo的数据成员并没有因此而初始化为0!

下来我们来深入探索下在Foo有默认构造函数的情形下,声明Bar对象时被合成的那个隐式有用的构造函数做了些什么:

它会按照有显式默认构造函数的成员对象在类中声明的顺序依次调用这些成员对象的显式默认构造函数,除此之外它什么也不做。

那么为Bar合成的那个隐式构造函数就应该看起来象这个样子:

inline Bar::Bar()


{


foo.Foo::Foo();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值