转化构造函数
如果构造函数只接受一个实参,则它实际上定义了转化为此类类型的隐式转换,我们把这种构造函数称作转换构造函数(converting constructor)。
举一个栗子
class A
{
public:
A(string _str):str(_str){} //这个只接受一个参数的构造函数就是转换构造函数
void Show() { //它定义了转化为此类类型的隐式转换
cout << str << endl;
}
private:
string str = "";
};
转化构造函数是这样实现隐式的类类型转换的
/*
EXAMPLE_1 参数隐式转换为类类型
*/
class Sales_data
{
public:
Sales_data(string _s):s(_s){} //转化构造函数
Sales_data &Combine(const Sales_data &cl) {
this->s += cl.s; //为什么这里有一个底层const???
return *this;
}
void Show()
{
cout << this->s <<endl;
}
private:
string s = "";
};
Sales_data obj("hello");
string str = " world";
obj.Combine(str).Show(); //Combine()本应接受一个Sales_data类的类型参数
//str通过转化构造函数隐式从string转化为Sales_data类类
//型,这个过程是通过创建一个临时的类的对象实现的
//而这个临时对象使用后就被清除
//我们可以把它看作是一个“字面值”,具有不可修改的属性
//因此传递引用参数时,必须有底层const
//输出hello world
/*
EXAMPLE_2 拷贝初始化时的隐式类类型转换
仍然沿用上面Sales_data类的定义
*/
string str = "hello";
Sales_data obj = str;
//string类型的str通过转换构造函数隐式转换为Sales_data类类型(临时常量)
隐式类类型转换的条件
只允许一步类类型转换
也就是这个转换过程中只可以有一次隐式转换
/*
一个失败的隐式类类型转换例子
沿用上面Sales_data类的定义
*/
Sales_data obj("hello ");
obj.Combine("world"); //error
//字面值“world”需要一次隐式转换为string类型
//string又需要一次隐式转换为Sales_data类型
/*
改写
*/
obj.Combine(static_cast<string>("world"));
//先使用强制类型转换把字面值“world”转换为string类型
一个疑问
Sales_data obj = "aaa"; //这样写仍然是可以的
explicit
通过explicit关键字可以禁止转换构造函数的隐式转化
explicit只能用于 转化构造函数
class A
{
public:
explicit A(string _s):s(_s){} //禁止了隐式类类型转换
private:
string s = "";
}
explicit构造函数只能用于直接初始化
A obj1("aaa"); //正确,直接初始化
A obj2 = "aaa"; //错误,禁止了隐式类型转换
Sales_data obj3("hello");
string str = " world";
obj3.Combine(str); //错误,禁止了隐式类型转换
仍然可以显示使用构造函数
obj3.Combine(static_cast<Sales_data>(str));