当前位置: 代码迷 >> PB >> 构造函数的初始化列表解决办法
  详细解决方案

构造函数的初始化列表解决办法

热度:88   发布时间:2016-04-29 08:19:22.0
构造函数的初始化列表
今天才知道构造函数还有初始化列表这种东西,很费解的是,构造函数本来就是来初始化的,为何变量的初始化不放在构造函数里面,
而要搞个什么初始化列表呢?
C/C++ code
class A{   int i,j;   public:    A(int a):i(a),j(a){}};


这个列表做的事情,我放到构造函数里面还不是一样吗?这样做有什么好处呢?

------解决方案--------------------
首先你应该知道
你并没有手动去为变量去申请内存
并做初始化动作
这些是编译器帮你做的

如果有初始化列表的话
编译器会帮你在申请内存的时候立即初始化

而写在构造函数里面
则是赋值行为,效率明显不及初始化列表高



------解决方案--------------------
在某些情况下可以互换
但在如下情况下必须用初始化列表对数据初始化:
常变量 引用变量 在继承体系中对父类数据的初始化
------解决方案--------------------
构造函数可能不止一个,包括系统默认的构造函数,还有拷贝构造函数,我们通常是在默认构造函数中进行初始化工作的,但是考虑到规范和简单等因素,所以使用初始化列表。
------解决方案--------------------
1.从概念上讲,可以认为构造函数分为两个阶段进行:1>.初始化阶段(在初始化列表中)2>.普通的计算阶段..计算阶段由构造函数中的函数体中所有语句组成...
2.不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化...其实也就是为类类型数据成员调用合适的构造函数...很显然,如果该数据成员没有重载赋值操作符,那么在普通的计算阶段就有可能发生意想不到的事..
3.可以初始化const对象或引用类型的对象,但不能对它们赋值(就构造函数的两阶段来说)..

------解决方案--------------------
转载一个 LZ看看
C++ Primer中在讲构造函数初始化列表的时候有这么一段话:
无论是在构造函数初始化列表中初始化成员,还是在构造函数体中对它们赋值,最终结果是相同的。不同之处在于,使用构造函数初始化列表的版本初始化数据成员,没有定义初始化列表的构造函数版本在构造函数体中对数据成员赋值。

请问这里的初始化数据成员与对数据成员赋值的含义是什么?有什么区别?

我知道在数据成员有默认构造函数时是有不同的,但对其他类型的成员呢?其他类型成员的初始化和赋值有区别吗?
========================================================================================
是这个意思:
首先把数据成员按类型分类
1。内置数据类型,复合类型(指针,引用)
2。用户定义类型(类类型)

分情况说明:
对于类型1,在成员初始化列表和构造函数体内进行,在性能和结果上都是一样的
对于类型2,结果上相同,但是性能上存在很大的差别
因 为类类型的数据成员对象在进入函数体是已经构造完成,也就是说在成员初始化列表处进行构造对象的工作,这是调用一个构造函数,在进入函数体之后,进行的是 对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)

举个例说明
class A;
class B
{public:
B(){a = 3;}
private:
A a;
}

class A
{public:
A(){}
A(int){value = 3;}
int value;
}

像上面,我们使a对象的value为3,调用一个A的构造函数+一个默认拷贝赋值符,才达到目的
B::B():a(3){}
像这样,只调用了一个构造函数就达到了所需的对象啦,所以性能好的 

转载他人一篇

我的问题是关于初始化C++类成员的。我见过许多这样的代码(包括在你的栏目中也见到过):

CSomeClass::CSomeClass()

{

x=0;

y=1;

}

而在别的什么地方则写成下面的样子:

CSomeClass::CSomeClass() : x(0), y(1)

{

}

我的一些程序员朋友说第二种方法比较好,但他们都不知道为什么是这样。你能告诉我这两种类成员初始化方法的区别吗?

回答

从技术上说,你的程序员朋友是对的,但是在大多数情况下,两者实际上没有区别。有两个原因使得我们选择第二种语法,它被称为成员初始化列表:一个原因是必须的,另一个只是出于效率考虑。

让我们先看一下第一个原因——必要性。设想你有一个类成员,它本身是一个类或者结构,而且只有一个带一个参数的构造函数。

class CMember {

public:

CMember(int x) { ... }

};

因为Cmember有一个显式声明的构造函数,编译器不产生一个缺省构造函数(不带参数),所以没有一个整数就无法创建Cmember的一个实例。

CMember* pm = new CMember; // Error!!

CMember* pm = new CMember(2); // OK

如果Cmember是另一个类的成员,你怎样初始化它呢?你必须使用成员初始化列表。

class CMyClass {

CMember m_member;

public:

CMyClass();

};

//必须使用成员初始化列表

CMyClass::CMyClass() : m_member(2)

{

???

}

没有其它办法将参数传递给m_member,如果成员是一个常量对象或者引用也是一样。根据C++的规则,常量对象和引用不能被赋值,它们只能被初始化。

第二个原因是出于效率考虑,当成员类具有一个缺省的构造函数和一个赋值操作符时。MFC的Cstring提供了一个完美的例子。假定你有一个类CmyClass具有一个Cstring类型的成员m_str,你想把它初始化为"yada yada."。你有两种选择:

CMyClass::CMyClass() {

// 使用赋值操作符

// CString::operator=(LPCTSTR);

m_str = _T("yada yada");

}

//使用类成员列表

// and constructor CString::CString(LPCTSTR)

CMyClass::CMyClass() : m_str(_T("yada yada"))
  相关解决方案