构造函数语义学
来源:互联网 发布:护眼有什么软件 编辑:程序博客网 时间: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.如果想要初始化这些非静态的内置数据类型成员,程序员需要自己去负责初始化
- C++ 构造函数语义学
- 构造函数语义学
- 构造函数语义学---default constructor
- 构造函数语义学----copy constructor
- 构造函数语义学之程序转化语义学(1)
- 构造函数语义学之程序转化语义学(2)
- 关于对象及构造函数语义学
- 深度探索C++对象模型第二章 构造函数语义学
- Inside The C++ Object Model---构造函数语义学
- 构造函数语义学之Default Constructor构建操作
- 构造函数语义学之Copy Constructor构建操作(1)
- 构造函数语义学之Copy Constructor构建操作(2)
- 深度探索C++对象模型--构造函数语义学
- 深度探索C++对象模型-构造函数语义学
- 深度搜索C++对象模型2.2 构造函数语义学-Default Constructor的构造操作
- 深度搜索C++对象模型2.2 构造函数语义学-Copy Constructor的构造操作
- C++ 虚函数语义学
- 《深度探索c++对象模型》学习笔记 - 2 构造函数语义学
- iOS移动端使用AES加密注意事项
- 修改centos系统时间为重庆时间(当前时间)
- 华为路由器dhcp简单配置实例
- c++中的string常用函数用法总结
- 使用 ubuntu builder
- 构造函数语义学
- xshell或putty上 按小键盘上的数字键并不能输入数字的解决办法
- JavaScript 中一些值的比较,熟悉规范
- spark:kmeans测试
- Error:(1, 0) Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRID
- 8B - Obsession with Robots
- Android中ProgressBar自定义进度条的高度、颜色、圆角
- jQueryUI中Datepicker(日历)插件的介绍和使用
- 在Activiti中使用UUID作为主键生成策略