一、前言:
一开始,我其实不打算把初始化列表单独拿出来写一篇文章的,我打算在创建一个类的那一篇文章里一起写掉,但是写着写着就发现事情没有我想的那么简单,这里面的内容还是比较多地。
二、初始化列表格式:
在构造函数里面可以通过初始化表的试来初始化成员属性
只有构造函数才有初始化列表
class 类名{
类名(形参列表):成员属性(形参变量),…{
}
类名(形参列表):初始化列表{
}
};
三、初始化列表的特点
1.对于类类型成员会自动在初始化列表中调用无参的构造函数;
在构造函数体里面其实只能对其进行赋值了;
#include <iostream>
using namespace std;
class Point{
private:
double x;
double y;
public:
Point(double x1,double y1):x(x1),y(y1){
cout << "Point(double,double)"<<endl;
}
Point():x(0),y(0){
cout << "Point()"<<endl;
}
};
class Circle{
private:
Point c;
double r;
public:
Circle(const Point& p,double r1):c(p),r(r1){
//c = p;
//r = r1;
}
//在初始化列表中调用指定的构造函数来实例化类类型成员变量
Circle(double x,double y,double r1):c(x,y),r(r1){//c(x,y)调用Point类的构造函数
//c = Point(x,y);
//r = r1;
}
};
int main(){
Circle c(1,1,1);//构造了几个Point的对象
return 0;
}
2.在初始化列表中可以调用指定的构造函数来初始化类类型的成员变量;
任意一个构造函数都会默认调用类类型的无参构造函数;
3.对于 常量成员 和 引用成员 必须通过初始化列表的形式来进行初始化;
#include <iostream>
using namespace std;
class CX{
public:
const int x;//常量成员
int& r; //引用成员
CX(int m,int& n):x(m),r(n){
//x = m;//Error
//r = n;//Error
cout << "CX" << endl;
}
};
int main(){
int x = 10;
CX(10,x);//匿名对象
return 0;
}
注意:参数列表非常重要,如果不使用参数列表,参数成员和引用成员根本没哟办法进行赋值操作;
4.成员初始化的顺序 与 初始化列表的 顺序无关 ;
只与成员声明的先后顺序有关
举个例子:
假设有一个类:
class C{
private:
B b;
A a;
public:
C():a(10),b(20){}
}
这个构造函数的调用顺序和参数列表中填写的顺序没有关系,即,不是先调用A类无参构造再调用B类无参构造;
这和成员声明的顺序有关,上面那个类里是先声明了b,再声明了a,所以是先调用B类的无参构造函数,再调用A类的无参构造函数;
5.假如没有用初始化列表
在初始化的时候,千万不能这样:
Circle(int x,int y){
x = x;
y = y;
}
这样是错的,在编译的时候就过不了;
只能:
Circle(int x1,int y1){
x = x1;
y = y1;
}
参数名字 和成员名称不能相同,但是如果用了参数列表情况将有所不同:
Circle(int x,int y):x(x),y(y){}
6.关于垃圾值
这就是4中构造顺序地问题,一定要搞清楚先构造的是哪一个,是按照成员声明顺序进行构造的!
#include <iostream>
using namespace std;
class P{
public:
int x;
int y;
P(int m):x(m),y(x){//x(m) y(x)
}
};
class X{
public:
int x;
int y;
//与初始化列表顺序无关 只与成员声明的先后顺序有关
X(int m):y(m),x(y){//x(y) y是垃圾值 x是垃圾值 y(m) y的值是m
}
};
int main(){
P p(10);
cout << p.x << "," << p.y << endl;//10,10
X x(10);
cout << x.x << "," << x.y << endl;//垃圾值,10
return 0;
}