再探 C++ 构造函数
深入探索 C++ 构造函数
1. 构造函数初始值列表
假设有一个 Person 类,它有私有变量 name, id, age.
现在有两种构造方式:
//Constructor 1
Person::Person(std::string& pName, int pAge) {
name = pName;
age = pAge;
}
//Constructor2
Person::Person(std::string& pName, int pAge):
name(pName), age(pAge) {}
第二种初始化方式,我们称为用初始值列表进行初始化,是一种对需要初始化的变量直接进行初始化的方式。
再来看看第一种初始化的方式,它的本质其实是先将变量 name, age 进行默认初始化,然后再进行赋值。
//Constructor1 等价于
Person::Person(std::string& pName, int pAge):
name(""), age(0) {
name = pName;
age = pAge;
}
所以,如果构造函数仅仅是用于初始化值的话,最好使用初始化列表进行初始化。
2. 委托构造函数
C++11 提供了委托构造函数,就是设置一个构造函数负责初始化所有的变量,其余的一些构造函数只需要调用这个构造函数即可。相当于其它的构造函数把自己的构造函数“委托”给了另一个构造函数一样。
还是以刚才的 Person 类为例:
//这个构造函数负责初始化所有的变量
Person::Person(std::string& pName, int pAge):
name(pName), age(pAge) {}
//其它的构造函数委托给上面的构造函数
Person::Person(std::string& pName): Person(pName, 0) {}
Person::Person(int pAge): Person("no name", pAge) {}
Person::Person(): Person("no name", 0) {}
3. 转换构造函数
转换构造函数的作用是将一个其他类型的数据转换成一个类的对象。
当一个构造函数只有一个参数,而且该参数又不是本类的 const 引用时,这种构造函数称为转换构造函数。
举个例子,假设一个复数类 Complex,两个私有变量: 实部 real,虚部 image.
class Complex {
private:
double real;
double image;
public:
//构造函数
Complex(double r, double i): real(r), image(i) {}
//默认构造
Complex(): Complex(0, 0) {}
//重载加号
Complex operator+(Complex& a);
};
3.1 隐式转换
我们希望的是,输入一个 double 的实数,它可以自动转换为一个虚部 image 为 0 的复数。所以这个时候,我们需要转换构造函数:
Complex::Complex(double r): Complex(r, 0) {}
这时候,用一个 Complex 和一个 double 变量相加,double 变量会被隐式转换为 Complex 类型。
//合法
Complex(2, 1) + 3.0;
3.2 抑制隐式转换 explicit
但有的时候,我们不希望进行隐式转换,这个时候,我们需要在构造函数之前加入 explicit 关键字。
class Complex {
private:
double real;
double image;
public:
//构造函数
Complex(double r, double i): real(r), image(i) {}
//默认构造
Complex(): Complex(0, 0) {}
//抑制隐式转换
explicit Complex(double r): Complex(r, 0) {}
//重载加号
Complex operator+(Complex& a);
};
印制了隐式转换,就只能进行显示构造,否则会报错。
//不合法, 无法隐式转换
Complex(2, 1) + 3.0;
//合法, 可以显式转换
Complex(2, 1) + Complex(3.0);
4. 聚合类
如果一个类,没有 private, protected 变量,没有基类,没有 virtual,没有自定义的构造函数,则它是一个聚合类,可以直接用列表初始化。
struct A() {
int a;
std::string b;
};
//初始化
A a = { 5, "Hello" };
Newest Posts