什么是C++中的初始化参数列表,它的作用是什么?
在 C++ 中,初始化参数列表(Initialization List)是一个构造函数的特性,用于初始化类成员变量和基类。它是在构造函数的声明中,以冒号(:
)开头,跟随一系列成员变量的初始化表达式的列表。
语法
构造函数():属性1(值1),属性2(值2)。。。{}
class ClassName {
public: ClassName(Type1 param1, Type2 param2) : member1(param1), member2(param2) { // 构造函数体 } private: Type1 member1; Type2 member2;
};
示例
class Point {
public: Point(int x, int y) : x_(x), y_(y) { // 初始化参数列表 // 构造函数体 } void print() { std::cout << "Point(" << x_ << ", " << y_ << ")" << std::endl; } private: int x_; int y_;
}; int main() { Point p(10, 20); p.print(); // 输出: Point(10, 20) return 0;
}
作用
高效初始化:
使用初始化参数列表可以直接在成员变量的构造过程中初始化对象,避免不必要的默认构造与赋值操作。例如,如果成员变量是一个类类型的对象,直接在初始化列表中进行初始化,可以避免先调用默认构造函数,再在构造函数体内进行赋值,从而提高性能。
不使用初始化参数列表:
#include <iostream>
class Father {
public:Father(){std::cout << "Father()" << std::endl;}~Father(){std::cout << "~Father()" << std::endl;}};class Son
{
public:Son(Father& value) //: m_a(value){std::cout << "Son()" << std::endl;m_a = value;}~Son(){std::cout << "~Son()" << std::endl;}
private:Father m_a;
};int main()
{Father f;Son s(f);return 0;
}//输出 :Father()Father()Son()~son()~Father()~Father()
使用初始化参数列表:
#include <iostream>
class Father {
public:Father(){std::cout << "Father()" << std::endl;}~Father(){std::cout << "~Father()" << std::endl;}};class Son
{
public:Son(Father& value) : m_a(value){std::cout << "Son()" << std::endl;//m_a = value;}~Son(){std::cout << "~Son()" << std::endl;}
private:Father m_a;
};
int main()
{Father f;Son s(f);return 0;
}输出:Father()Son()~son()~Father()~Father()
少调用了一次父类构造。
初始化常量和引用:
常量成员变量(const
)和引用成员变量(&
)必须在初始化列表中进行初始化,因为它们在初始化后不能被更改。
class Example {
public: Example(int value) : constMember(value), refMember(otherValue) { // 这里,constMember 和 refMember 必须在初始化列表中初始化 } private: const int constMember; int& refMember;
};
初始化基类:
当继承自一个基类时,可以在构造函数的初始化列表中指定基类的构造函数,确保基类成员在派生类构造之前被正确初始化。
class Base {
public: Base(int value) { // 基类构造 }
}; class Derived : public Base {
public: Derived(int value) : Base(value) { // 初始化基类 // 派生类构造 }
};
初始化队列:
成员变量的初始化顺序是按照它们在类中声明的顺序,而不是在初始化列表中的顺序。这一点很重要,因为如果存在依赖于其他成员变量的初始化顺序时,使用初始化列表可能会引起问题。
给父类的构造函数传参
class A
{public:A(int a){};
};
class father
{public:father(int a){};
};
class son:public father
{
A a; //成员对象
public:
son(int num,int p):father(num),a(p) {}
}
int main()
{son s(3,4); //3是给父类的构造传的,4是传给成员对象的构造函数
}
注意事项
1.初始化的顺序和初始化参数列表中的顺序无管,和变量声明顺序一致
class A {int a;int b;int c;
public://初始化参数列表 是初始化成员变量的/*初始化的顺序和初始化参数列表中的顺序无管,和变量声明顺序一致*/A(int a1,int b1):a(b),c(b1),b(a1){cout << a << " " << b << " " << c;
}int main() {A(1, 2);return 0;}
//结果:-858993460(错误) 1 2
2.在类成员中存在常量,如const int a,只能通过初始化列表进行初始化,不能使用赋值的方式。
//例如:
class A
{
public:A(const int a){data_a = a;//常量无法作为赋值符号的左值}
private:const int data_a;
};//出错
3.对于类成员中存在引用的情况,同样只能使用初始化列表赋值,不能直接进行赋值操作。
//例如
class A
{
public:A(int& a){}
private:int& data_a;
};
//出错//正确写法
class A
{
public:A(int& a):data_a(a){}
private:int& data_a;
};
有什么问题,小伙伴们可以在评论区进行讨论并留言。