为什么 没有缺省构造函数的类类型成员 必需要在初始化列表 里初始化 ?
Posted _NiuLi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么 没有缺省构造函数的类类型成员 必需要在初始化列表 里初始化 ?相关的知识,希望对你有一定的参考价值。
名词解释
1、缺省构造函数:类的构造函数无参或参数默认值统称为缺省构造函数。
2、初始化列表:与其它函数不同,构造函数除了有名字,参数列表和函数体外还可以有初始化列表。列表以冒号开始后跟以逗号隔开的初始化字段。类成员是在构造函数的初始化列表创建好的,在创建类成员的同时,给成员变量一个初始化值。
在解释原因之前,需要了解构造函数是如何执行的
构造函数的执行过程
首先,构造函数的执行分为三步。先创建函数的形参(如果没有形参这步可以省略),然后执行初始化列表(即使没有初试化列表),最后执行函数体的内容。
没有初始化列表时,系统在创建类成员时会给成员一个初值。根据对象的作用域不同,初值也不同。代码证明请见附录1
(1)全局的对象和局部的static对象,系统会对 int类型的成员赋初值0,指针类型的成 员赋初值0x00000000。
(2)除static类型外的局部对象,系统对成员赋一个随机值。
在执行函数体时,类成员已被创建好,并且有一个初值。函数体内给成员值时不是初始化,而是赋值。
可以通过下面的代码证明证明这一问题。
下面先给类B一个默认参数,这样就不需要在A的构造函数的初始化列表里初始化B类型的A成员。
#include <iostream>
#include <cstdlib>
using namespace std;
class B
public:
B(int data=0)
:_data(data)
cout << "B()" << endl;
B(const B &b)
:_data(b._data)
cout << "B(const B &)" << endl;
B & operator=(const B &b)
cout << "operator=" << endl;
_data = b._data;
return *this;
~B()
cout << "~B()" << endl;
private:
int _data;
;
class A
public:
A(B data = 1)
b = data;
cout << "A()" << endl;
~A()
cout << "~A()" << endl;
private:
B b;
;
int main()
A a(2);
system("pause");
return 0;
上述代码进行调试时,通过this指针和窗口可以看到main函数内是这样执行的:
1、用类A创建对象a,调用A的构造函数。
执行类A的构造函数分三步。
(1) 为构造函数的形参开辟空间,因形参时类B类型的对象,故创建形参时要调用B的构造函数
(2) 执行A的构造函数的初始化列表(即使没有初始化列表),创建对象a的成员b,并赋初值。因成员b又是一个类类型的对象,创建b时会调用B的构造函数。B的构造函数执行完后,到此,A的构造函数的初始化列表已执行完毕。
(3) 执行A构造函数的函数体。执行b=data,调用赋值运算符重载函数 ;然后执行cout <<"A()"<<endl;
因形参时构造函数内的对象,在执行完构造函数时要调用形参data的析构函数。到此,构造函数执行完毕。
2、对象a创建好后,要出a的作用域,调用A的析构函数,并且a的成员b也要调用B的析构函数。
3、最后执行完程序屏幕输出的内容如下:
为什么没有缺省构造函数的类类型成员要在初始化列表初始化
下面的代码中,类B没有缺省的构造函数,在类A中有一个类B类型的成员
#include <iostream>
#include <cstdlib>
using namespace std;
class B
public:
B(int data)
private:
int _data;
;
class A
public:
A(int data=0)
private:
B _b;
;
int main()
A a;
system("pause");
return 0;
上述代码在执行时会报错。这是因为:
在main() 中创建A类型对象a时要执行的构造函数,先创建形参,然后执行初始化列表。
那么问题来了,初始化列表中要创建a的成员b并给b一个初值,那么就要调用B的构造函数。这时,因为已有构造函数系统不会生成默认的构造函数,而已写的构造函数必需要一个参数,此时初始化列表中并没有可以提供给B的构造函数的参数,故创建b时会出错。
必需在初始化列表初始化的成员还有:
☆常量成员
☆引用类型成员变量。
有了上面的基础后这就很好理解,初始化列表中要创建类成员并赋初值,而常量和引用类型的变量必需在创建时给一个值,常量在创建好后不能改变,引用必需在创建时初始化。
附录1:
系统默认构造函数,给类对象的成员赋初值的情况
#include <iostream>
#include <cstdlib>
using namespace std;
class Test
public:
void Display()
cout <<"_p = "<< _p << endl;
cout<<"_data = "<< _data << endl<<endl;
private:
int * _p;
int _data;
;
Test test1;
int main()
Test test2;
static Test test3;
cout << "test1 : "<<endl;
test1.Display();
cout << "test2 :"<<endl;
test2.Display();
cout << "test.3 :"<<endl;
test3.Display();
system("pause");
return 0;
本文出自 “牛丽” 博客,请务必保留此出处http://15129279495.blog.51cto.com/10845420/1759816
以上是关于为什么 没有缺省构造函数的类类型成员 必需要在初始化列表 里初始化 ?的主要内容,如果未能解决你的问题,请参考以下文章