C++构造函数 初始化列表
1.对象初始化列表
(1)对象初始化列表出现原因:
- 1.1 必须这样做:如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,没有默认构造函数。这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数。
如果没有初始化列表,那么他将无法完成第一步,就会报错。 - 1.2类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值,当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化。因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如
class CExample {
public:
int a;
float b;
//构造函数初始化列表
CExample(): a(0),b(8.8)
{}
//构造函数内部赋值
CExample()
{
a=0;
b=8.8;
}
};
上面的例子中两个构造函数的结果是一样的。
- (使用初始化列表的构造函数)显式的初始化类的成员;
- 而没使用初始化列表的构造函数是对类的成员赋值,并没有进行显式的初始化。
初始化和赋值对内置类型的成员没有什么大的区别,像上面的任一个构造函数都可以。对非内置类型成员变量,为了避免两次构造(初始化+赋值),推荐使用类构造函数初始化列表。但有的时候必须用带有初始化列表的构造函数:
-
- 成员类型 是没有默认构造函数的类,此时必须提供成员类型的初始化列表,因为若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。
-
2.const 成员或引用类型的成员。因为 const 对象或引用类型只能初始化,不能对他们赋值。
例子:
class A{
public:
A(int x){
i = x;
cout<<"Object is being created";
}
int i;
}
class B{
public:
B(int x){
j = x;
cout<<"Object is being created";
}
int j;
A a; // error “A”: 没有合适的默认构造函数可用
}
int main(){
B b(5);
return 0;
}
类B数据成员中函数自定义数据类型A,创建B对象时,要先创建其成员对象a,A类有参数化的构造函数,则编译器不会提供默认无参数的构造函数,因此a的构造函数出错,即a无法创建;
对成员对象正确的初始化方法是通过显示方式进行,B的构造函数应该写成:
B(int y, int z) : a(z)
{
j = y;
}
B b(5,10);
构造函数初始化列表是初始化 常数据成员 和 引用成员 的唯一方式。因为const对象或引用类型只能初始化,不能对他们赋值。
class A
{
public:
A (int x,int y) : c(x),j(y) // 构造函数初始化列表
{
i = -1;
}
// error
A (int x) // 构造函数初始化列表
{
i = -1;
c = 5; //必须在构造函数基/成员初始值设定项列表中初始化
j = x; //必须在构造函数基/成员初始值设定项列表中初始化
}
private:
int i;
const int c;
int& j;
};
int main( )
{
int m;
A a(5,m);
return 0;
}
缺省情况下,在构造函数的被执行前,对象中的所有成员都已经被它们的缺省构造函数初始化了。当类中某个数据成员本身也是一个类对象时,我们应该避免使用赋值操作来对该成员进行初始化:
class Person
{
private:
string name;
public:
Person(string& n)
{
name = n;
}
}
虽然这样的构造函数也能达到正确的结果,但这样写效率并不高。当一个Person对象创建时,string类成员对象name先会被缺省构造函数进行初始化,然后在Person类构造函数中,它的值又会因赋值操作而在改变一次。我们可以通过初始化列表来显示地对name进行初始化,这样便将上边的两步**(初始化和赋值)**合并到一个步骤中了。
class Person
{
private:
string name;
public:
Person(string& n): name(n){}
}
- 提供默认无参数构造函数 和 有参数构造函数
class Interval{
public:
int start;
int end;
Interval(int s,int e):start(s),end(e){
cout<<"user creat func"<<s<<":"<<e<<endl;
}
Interval():start(0),end(0){
cout<<"default creat func"<<endl;
}
};
int main(){
Interval cc(1,5);
cout<<cc.start<<cc.end<<endl;
Interval dd;
cout<<dd.start<<dd.end<<endl;
}