explicit构造函数的作用
本文通过几个例子解释了explicit关键字在构造函数中的作用。
1. 构造函数的隐式转换
C++的默认规定,如果构造函数只接受一个实参,则它实际上定义了转换为此类型的隐式转换机制。(但是只允许一步类类型转换)
// C++ Primer
class Sales_data {
Sales_data(string s) {}
}
void func(Sales_data a);
int main() {
Sales_data test("999999"); // 编译通过,"999999"隐式转换为string,再调用构造函数
func("999999"); // 编译错误,
// 1)把"999999"转化为string
// 2)把临时string转为Sales_data
func(string("999999")); // 编译通过,这里把string隐式转换为了Sales_data
}
2. 隐式转换的坑
假设我们要实现一个复数类,然后我们定义了一个Complex类
#include <iostream>
using namespace std;
class Complex
{
private:
double real;
double imag;
public:
// Default constructor
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// A method to compare two Complex numbers
bool operator == (Complex rhs) {
return (real == rhs.real && imag == rhs.imag)? true : false;
}
};
int main()
{
// a Complex object
Complex com1(3.0, 0.0);
if (com1 == 3.0)
cout << "Same";
else
cout << "Not Same";
return 0;
}
// 结果输出Same
很明显,com1 == 3.0此处发生了一次隐式转换,然后3.0转换为了Complex(3.0, 0.0)所以最后输出了Same。
3. explicit作用
如果我们想避开这个坑,那就用explicit来抑制构造函数的隐式转换。
class Complex
{
private:
double real;
double imag;
public:
// Default constructor
explicit Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// A method to compare two Complex numbers
bool operator== (Complex rhs) {
return (real == rhs.real && imag == rhs.imag)? true : false;
}
};
// 此时再运行com1 == 3.0,就会有报错了
// error: invalid operands to binary expression ('Complex' and 'double')
4.其他例子
class String {
String(int n) {} //本意是预先分配n个字节给字符串
String(const char* p) {} // 用C风格的字符串p作为初始化值
}
下面两种写法比较正常:
String s2(10); //OK 分配10个字节的空字符串
String s3 = String(10); //OK 分配10个字节的空字符串
下面两种写法就比较疑惑了:
String s4 = 10; //编译通过,也是分配10个字节的空字符串
String s5 = ‘a’; //编译通过,分配int(‘a’)个字节的空字符串
s4 和s5 分别把一个int型和char型,隐式转换成了分配若干字节的空字符串,容易令人误解。
为了避免这种错误的发生,我们可以声明显示的转换,使用explicit 关键字:
class String {
explicit String(int n) {} //预先分配n个字节给字符串
String(const char* p) {} // 用C风格的字符串p作为初始化值
}
加上explicit,就抑制了String(int n)的隐式转换,
下面两种写法仍然正确:
String s2 (10); //OK 分配10个字节的空字符串
下面两种写法就不允许了:
String s4 = 10; //编译不通过,不允许隐式的转换
String s5 = ‘a’; //编译不通过,不允许隐式的转换
所以,explicit可以有效地防止构造函数的隐式转换带来的错误和误解