首先 放另外一个博主的链接:http://www.cnblogs.com/graphics/archive/2010/07/04/1770900.html
在学习c++构造函数的过程中遇到了初始化列表这个词,便主动搜索资料,学习初始化列表这个概念
一、初始化列表的由来
在构造函数中,除了 函数名,函数体外,可以有初始化列表,也可以没有初始化列表,初始化列表不是必须的。
struct Test
{
public:
Test(string n, int b): name(n), id(b){};//初始化列表的表现形式 :初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段
// Test(string n, int b)
// {
// name = n;// id = b;
//} 一般的构造函数
private:
string name;
int id;
};
在构造函数中,构造函数分两步给成员变量赋值,第一是初始化阶段,第二是计算阶段,并且初始化阶段在前,计算阶段在后。
初始化阶段:
所有类类型(class type)的成员都会在初始化阶段初始化,即使该成员没有出现在构造函数的初始化列表中。意思需初始化的成员没有在初始化列表中,就会调用相应的构造函数来进行初始化,如默认构造函数,一般带参构造函数,复制构造函数,类型转换构造函数等。
计算阶段:
一般用于执行构造函数体内的赋值操作
我理解的赋值操作就是构造函数中函数体内部的操作,
struct Test1 {
Test1() // 无参构造函数
{ cout << "Construct Test1" << endl ;
}
Test1(const Test1& t1) // 拷贝构造函数
{ cout << "Copy constructor for Test1" << endl ;
this->a = t1.a ;
}
Test1& operator = (const Test1& t1) // 赋值运算符
{
cout << "assignment for Test1" << endl ;
this->a = t1.a ;
return *this;
}
int a ;
};
struct Test2 {
Test1 test1 ; //成员变量
Test2(Test1 &t1) //构造函数
{ test1 = t1 ;
}
};
执行代码:
Test1 t1; // 会调用Test1 的默认构造函数,打印 Construct Test1
Test2(t1); //打印Construct Test1:因为 Test2 中有 test1 的成员变量,在它的初始化阶段 会调用Test1 默认的构造函数,
// 打印 assignment for Test1 , 是在调用Test2的构造函数阶段, 赋值操作,用到的是=号的重载。
二、成员变量如何初始化
1、用初始化列表初始化, 初始化列表是用来初始化成员变量的。
2、在构造函数中,用赋值语句进行初始化。
三、初始化列表有什么好处
使用初始化列表主要是基于性能问题,使用初始化列表少了一次调用默认构造函数的过程,当成员变量多的时候,这样比较快。快才是硬道嘛。
struct Test2{ Test1 test1 ; Test2(Test1 &t1):test1(t1){}}
这样写的话,Test2的初始化列表,直接调用拷贝构造函数初始化test1,就不会调用Test1 的默认构造函数了。 这样效率更高。
四、那些必须使用初始化列表初始化
1、常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
2、引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面。
3、没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
注:没有默认构造函数的类的类型如果不用初始化列表来初始化就会调用默认的构造函数,但是它又没有默认的构造函数,就会报错。----billadd
大牛总结:
1. 如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数, 而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数, 如果没有初始化列表,那么他将无法完成第一步,就会报错。
2、类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值 当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化, 因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
举例:
struct Test2
{ Test1 test1;Test1 &aaa;
const int m; Test2(Test1 &t1):test1(t1), m(10),aaa(test1){}};
五、类中变量初始化的顺序
成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的
struct foo{ int i ; int j ; foo(int x):i(x), j(i){}; // ok, 先初始化i,后初始化j};
个人总结:
1、构造函数中可以有初始化列表,也可以没有初始化列表
2、构造函数分为初始化和计算两个阶段,初始化阶段在前,计算阶段在后。
3、用初始化列表初始化变量比一般的赋值函数快,因为省去了调用默认构造函数。
4、常量变量、引用、无默认构造函数的类,必须用初始化列表初始化。
5、初始化列表的顺序,是根据在类中出现的顺序初始化的。
备注:dm10_init_list.cpp