本博客将讲述C++初始化列表的相关内容
一.什么是初始化列表
图中红方框框的就是初始化列表
格式为:
:成员变量1(参数1),成员变量2(参数2)
编译器会将初始化列表一一转换成代码,并将这些代码放在用户编写的代码之前。
初始化列表的效果:
在类定义中声明成员变量时,不建议使用初始化语句进行初始化(例如int x = 0),因为这种初始化方式将在构造函数调用之前执行,可能会导致其他部分的代码不能引用该成员变量的问题。初始化列表的方式是一种更好的初始化数据成员的方式,因为它将初始化操作与构造函数调用分开,可以保证成员变量的正确使用。使用初始化列表可以提高程序的效率和可读性,因为它可以避免在构造函数体中进行初始化,从而减少了构造函数的执行时间。使用初始化列表还可以确保各个成员变量被正确地初始化,从而避免因未初始化导致的错误。
二.什么时候使用初始化列表
1.有成员变量是引用类型时;
下图是使用了初始化列表的结果,编译成功。
2.当有数据成员是常量时;
类的数据成员有常量(const)时,必须使用初始化列表。
3.当父类的构造函数有参数时,在子类构造函数中使用初始化列表初始化父类参数;
class Base {
public:
Base(int x) : _x(x) {}
private:
int _x;
};
class Derived : public Base {
public:
Derived(int x, int y) : Base(x), _y(y) {}
private:
int _y;
};
父类的构造函数有参数时,子类若不使用初始化列表来初始化继承父类的成员,而是在构造函数体内调用父类构造函数,会报错。
但是如果父类的构造函数是全缺省,不会报错(注意参数数量)(代码如下图)
三.初始化列表的顺序
编译器会将初始化列表一一转换成代码,并将这些代码放在用户编写的代码之前。
注意: 初始化列表的初始化顺序是由数据成员的声明次序决定的,不是由初始化列表的排列次序决定的。
class B
{
private:
int i;
int j;
public:
B(int value):j(value),i(j)
{
cout << "i = " << i << endl;
cout << "j = " << j << endl;
}
};
int main()
{
B objC(10);
return 0;
}
结果如下:
上述程序代码看起来像是要把 j 设初值为 value,再把 i 设初值为 j.问题在于,由于声明次序的原因,初始化列表中的”i (j)”其实比”j(value)”更早执行。但因为j 一开始未有初值,所以i(j)的执行结果导致无法预知其值。就输出随机值。
如何改进呢?将复制代码写在函数体中
class B
{
private:
int i;
int j;
public:
B(int value):j(value)
{
i = j;
cout << "i = " << i << endl;
cout << "j = " << j << endl;
}
};
int main()
{
B objC(10);
return 0;
}
注意:不能在子类构造函数的初始化列表中使用子类的成员函数给父类传参(除非该成员函数是返回常数,例如:Getage(){return 3}但这样没有意义)代码如下:
class Animal {
public:
Animal(int _age) : age(_age) {}
int age;
};
class Cat : public Animal {
public:
Cat() : Animal(getAge()), age(3) {}
void Print()
{
cout << Animal::age<<endl << Cat::age << endl;
}
private:
int age;
int getAge() { return age; }
};
int main()
{
Cat A;
A.Print();
return 0;
}
结果如下:
根据类成员在类中的声明顺序,在初始化列表中,父类的构造函数先执行(不管放在前还是后,所以建议放在最前)无法正确传参,所以传随机值。所以父类的构造函数要放在最前面,方便检查。
少年没有乌托邦,心向远方自明朗!
如果这个博客对你有帮助,给博主一个免费的点赞就是最大的帮助❤
欢迎各位点赞,收藏和关注哦❤
如果有疑问或有不同见解,欢迎在评论区留言❤
后续会继续更新大连理工大学相关课程和有关C++的内容和代码
点赞加关注,学习不迷路,好,本次的学习就到这里啦!!!
我们下次再见!