构造函数是为了方便类的初始化而存在,而初始化时会遇到const成员变量、引用成员变量等,这些变量不允许函数内赋值,必须要在初始化时进行赋值,所以就有了初始化列表,初始化列表只能存在于类的构造函数中,用于对类的成员变量进行初始化,尽量使用初始化列表初始化,因为不管是否使用初始化列表,成员变量一定会先使用初始化列表初始化。
初始化列表
- 格式
class A
{
public:A():成员变量1(参数1或表达式),成员变量2(参数2或表达式), .......{}
}
-
构造体函数内初始化和初始化列表初始化正常使用情况下来说没有太大区别,但是有三种情况一定要使用初始化列表来初始化,否则编译器会报错。
- const成员变量
- 引用成员变量
- 没有默认构造函数的自定义类型
前两个类型只能在初始化时给值,而初始化是在初始化列表中进行,在构造函数内给值相当于更改const或改引用,这都是禁止的。
代码会输出什么?
class A
{public:A(int a):_a2(a),_a1(_a2){}void Print() {cout<<_a1<<" "<<_a2<<endl;}private:int _a1;int _a2;
};
int main() {A aa(1);aa.Print();
}
成员变量在初始化列表中的初始化顺序取决于其在类中的声明顺序,于其在初始化列表中的顺序无关,所以这段代码会输出,随机值 1
构造函数体内初始化与列表初始化运行上的的区别
使用构造函数体内初始化
class A {
public:A() {cout << "A Default Constructor" << endl;}A(int a) {_a = a;cout << "A Constructor" << endl;}A(const A&) {cout << "A Copy Constructor" << endl;}A& operator=(const A& a) {cout << "A Assign Operator" << endl;_a = a._a;return *this;}~A() {cout << "A Deconstructor" << endl;}
private:int _a;
};class B {
public:B() {cout << "B Default Constructor" << endl;}B(A &a) {cout << "B Constructor" << endl;a1 = a;}
private:A a1;
};int main()
{A a;B b(a);
}
运行结果:
A Default Constructor
//40行定义类调用A的默认构造A Default Constructor
//由41行进入30行,首先调用B的默认构造,由于B中存在成员函数A类型,对A进行定义并初始化所以调用A的默认构造B Constructor
//接着上面走,走到31行输出A Assign Operator
//由32行赋值运算符进入13行赋值运算符重载函数,进行输出A Deconstructor
//main函数结束销毁A Deconstructor
//main函数结束销毁
使用初始化列表初始化
class A {
public:A() {cout << "A Default Constructor" << endl;}A(int a) {_a = a;cout << "A Constructor" << endl;}A(const A&) {cout << "A Copy Constructor" << endl;}A& operator=(const A& a) {cout << "A Assign Operator" << endl;_a = a._a;return *this;}~A() {cout << "A Deconstructor" << endl;}
private:int _a;
};class B {
public:B() {cout << "B Default Constructor" << endl;}B(A& a) :a1(a){cout << "B Constructor" << endl;}
private:A a1;
};int main()
{A a;B b(a);
}
运行结果:
A Default Constructor
//41行定义AA Copy Constructor
//由于直接在初始化列表初始化赋值,所以直接调用拷贝构造函数B Constructor
//接着上面运行输出A Deconstructor
//main函数结束销毁A Deconstructor /
/main函数结束销毁
可以看到构造函数体内初始化和初始化列表初始化的区别就是前者是先走默认的初始化列表进行定义(调用默认构造函数),然后再赋值(调用赋值重载),后者直接在初始化列表进行定义并初始化,所以直接调用拷贝构造函数。所以省去了一个步骤,显然使用初始化列表进行初始化更优
✨本文收录于C++语法及练习
当你喜欢一篇文章时,点赞、收藏和关注是最好的支持方式。如果你喜欢我的文章,请不要吝啬你的支持,点赞👍、收藏⭐和关注都是对我最好的鼓励。感谢你们的支持!如有问题欢迎指正!