首页 > 编程笔记
C++构造函数的初始化列表
在 C++ 中,构造函数负责初始化新创建的对象。然而,除了构造函数体中的赋值操作,C++ 还提供了一种更高效、更精确的方式来初始化成员变量,叫做初始化列表。
初始化列表紧跟在构造函数参数列表的后面,以一个冒号开头,然后是成员变量及其初始值,初始值用圆括号包裹着。例如,MyClass 类的构造函数以初始化列表的方式为各个成员变量赋初值:
搞清楚以上两种初始化方式的区别之后,如果类中有 const 或引用类型的成员变量,必须使用初始化列表来初始化它们,因为这些类型的成员变量在创建后就不能更改。
例如:
使用初始化列表时,有一些需要注意的地方:
初始化列表紧跟在构造函数参数列表的后面,以一个冒号开头,然后是成员变量及其初始值,初始值用圆括号包裹着。例如,MyClass 类的构造函数以初始化列表的方式为各个成员变量赋初值:
class MyClass { public: MyClass(int a, double b) : m_a(a), m_b(b) {} // 初始化列表 private: int m_a; double m_b; };在 C++ 中,构造函数的初始化列表是非常有用的,这点让初学者非常疑惑,因为下面的语句也能达到同样的目的,且更加直观:
MyClass(int a, double b){ m_a = a; m_b = b; }上面两种方法是有区别的,初始化列表的方式对每个变量只有一次初始化,而后一种方法则先用默认值初始化,然后再赋相应的值,也就是说在进入构造函数之前已经完成了初始化。因此,使用初始化列表的效率更高。
搞清楚以上两种初始化方式的区别之后,如果类中有 const 或引用类型的成员变量,必须使用初始化列表来初始化它们,因为这些类型的成员变量在创建后就不能更改。
例如:
class MyClass { public: MyClass(int a, const std::string& s) : m_a(a), m_s(s) {} private: int m_a; const std::string m_s; // 必须使用初始化列表 };
初始化列表的完整实例
下面的例子中定义了一个 Point 类,用来表示在三维坐标系统下的一个点,类的构造函数可以接收 3 个参数,或者忽略 z 坐标,或者不提供初始化参数。#include <iostream> using namespace std; class Point { friend ostream& operator << (ostream & out, const Point & p); //输出函数 public: // 3 个参数的构造函数 Point(int x, int y, int z) :m_x(x), m_y(y), m_z(z) { cout << "3 个参数的构造函数被调用" << *this << endl; //输出数据 } // 2个参数的构造函数 Point(int x, int y) :m_x(x), m_y(y), m_z(0) { cout << "2个参数的构造函数被调用" << *this << endl; //输出数据 } //无参数的构造函数 Point() :m_x(0), m_y(0), m_z(0) { cout << "无参数的构造函数被调用" << *this << endl; } // 复制构造函数 Point(const Point& p) :m_x(p.m_x), m_y(p.m_y), m_z(p.m_z) { cout << "复制构造函数被调用" << *this << endl; //输出数据 } private: int m_x, m_y, m_z; }; //重载输出操作符 ostream& operator<<(ostream& out, const Point& p) { out << "x = " << p.m_x << "y = " << p.m_y << "z = " << p.m_z; return out; } Point fun(Point p) { return p; } int main(){ Point pl; Point p2(10, 10); Point p3(10, 10, 10); Point p4 = p2; fun(p3); }执行结果为:
无参数的构造函数被调用x = 0 y = 0 z = 0
2个参数的构造函数被调用x = 10 y = 10 z = 0
3 个参数的构造函数被调用x = 10 y = 10 z = 10
复制构造函数被调用x = 10 y = 10 z = 0
复制构造函数被调用x = 10 y = 10 z = 10
复制构造函数被调用x = 10 y = 10 z = 10
总结
构造函数的初始化列表是 C++ 中一种强大而灵活的特性,它不仅提高了代码的执行效率,还为成员变量的精确初始化提供了更多控制。使用初始化列表时,有一些需要注意的地方:
- 不是所有的数据成员都必须出现在初始化列表中;
- 初始化列表中每个成员只能出现一次,不可以重复初始化;
- 数据成员在初始化列表中的出现顺序与类中定义的顺序无关;
- 如果类中有 const 或引用类型的成员变量,必须使用初始化列表来初始化它们。