构造函数语义学

来源:互联网 发布:护眼有什么软件 编辑:程序博客网 时间:2024/06/13 15:31

c++在一个类没有申明构造函数的时候会为其申明一个默认的构造函数,但是这个构造函数是无用的,并不会初始化这个类中的内置类型的成员。

参考一下代码:

//默认构造函数测试#include<iostream>using namespace std;class Foo{public:    int val;    Foo *ptr;};int main(){    Foo foo;    if(foo.val || foo.ptr)        cout<<"参数没有初始化"<<endl;    else        cout<<"参数初始化wei为0"<<endl;    return 0;}       

在调试的发现如图所示:


发现一个类自己生成的默认构造函数并不会初始化内置数据类型。也就是在原书中所说的这样的默认构造函数通常是一trivial的构造函数。当然c++标准也说明了在什么情况下,产生的默认构造函数是有效的,情况有如下四种:

-----------------------------------------------------------------------------------------------------------------

(1)一个类的成员变量为一个对象类型且这个成员对象含有默认的构造函数

当一个类没有定义构造函数,但是它含有一个成员对象,这个成员对象有default constructor,那么这个时候,这个class的隐式产生的默认构造函数就是有效的。编译器会为这个class合成一个默认的构造函数,不过合成的操作只有真正在需要被调用的时候才会发生。

比如说如下的代码:

#include<iostream>using namespace std;class Foo{public:    Foo(){val=0,ptr=NULL;}    int val;    Foo *ptr;};class Bar:public Foo{public:    Foo foo;    char *str;};int main(){    Bar bar;    if(bar.foo.val || bar.foo.ptr)        cout<<"bar.foo参数没有初始化"<<endl;    else        cout<<"bar.foo参数初始化为0"<<endl;    if(bar.str)        cout<<"bar.str 没有被初始化为0"<<endl;    else        cout<<"bar.str 被初始化为0"<<endl;    return 0;}       

运行的效果如下所示:


这说明当一个类其中含有对象类型的时候,这个类产生的默认构造函数是有效的。Bar被合成的默认构造函数会调用Foo的默认构造函数来处理bar的成员变量foo,但是Bar的默认构造函数并不会产生代码来初始化Bar::str。

这里需要注意几个问题:

1.被合成的默认构造函数只是满足了编译器的需要,并不满足程序的需要,因为通常你也需要初始话str指针。

2.假如程序员自己定义了默认构造函数来初始化str,比如

Bar::Bar(){str=0;}
这个时候由于已经定义了默认的构造函数,所以编译器不会为Bar合成默认的构造函数了,但是还是需要初始化成员对象。这个时候编译器做的事情是会扩张已经存在的构造函数(默认构造函数或者其他自己定义的构造函数),在其中安插一些代码,使得在user code被执行之前,先调用成员对象的默认构造函数,这个时候代码可能如下:

Bar::Bar(){      foo.Foo::Foo();      str=0;}

3.如果有多个成员对象都需要初始化操作,这个时候安插的代码结构会按照各个成员对象在类中的申明的顺序来调用各个成员对象的默认构造函数。

-----------------------------------------------------------------------------------------------------------------
(2)一个类的基类带有默认的构造函数

如果一个没有任何构造函数的class派生自一个带有默认构造函数的base class,那么这个派生类的默认构造函数被视为有效的,被编译器合成。它将调用基类的默认构造函数来初始化派生类中基类的部分。

注意:

如果派生类有多个构造函数,并没有定义默认的构造函数的话,编译器此时就不会为派生类合成默认的构造函数,但是会扩张每一个构造函数,在其中加入调用基类默认构造函数的程序代码。

(3)如果一个class它自己或者是他的父类含有vitual函数

这个时候需要编译器为一个类的对象初始化vptr执行这个类的虚函数表vtbl


(4)如果一个class来自于虚拟继承,也就是说它含有虚基类

这个时候需要编译器为这个class的对象合成一个虚基类指针,执行它的虚基类。


总结:

上面的4种情况,会使得编译器为没有声明构造函数的类合成一个默认的构造函数。在c++标准种把这些合成物称之为隐式有效的默认构造函数。但是被合成的默认构造函数只满足编译器的需要,并不能满足程序员的需要。至于除了这4中情况之外而又没有声明任何构造函数的class,在这本书中说他们拥有的是一个隐式的无效的默认构造函数,实际上编译器不会去合成他们

1.合成的默认构造函数中,只有base class subobject和member class object会被初始化(使用他们的默认构造函数),其余的非静态数据不会被初始化(如整数,整数指针等)

2.如果想要初始化这些非静态的内置数据类型成员,程序员需要自己去负责初始化



0 0
原创粉丝点击