class Demo{
public:
Demo() {
}
Demo(const string& tt) {
cout << "abc";
}
};
void func(Demo a) {
cout << "aaa";
}
void main(){
func("aaa");
}
显示上图中的错误,首先我们分析一下这个代码。
每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。如果构造函数只接受一个参数,且这个参数不是该类的对象引用,则它实际上定义了转换为此类型的隐式转换机制,一般称之为转换构造函数。所以代码中以string为形参的构造函数就是一条string转换为Demo类型的转换构造函数。
string str = "aaa";
func(str);
如果我们先定义一个string变量,然后将这个变量传递给func。首先发生的是string->Demo类型的转换,然后作为函数实参传递给参数。这是可行的。
func(“aaa”); //报错
func(string(“aaa”)); //可行
为什么将字符串显示地转换成string,就允许充当func函数的参数,而字符串本身不允许。
为了解决这个问题,我们首先查阅一下字符串字面值到底是什么?
因为某些历史原因,也为了与C兼容,所以C++语言的字符串字面值并不是标准库类型string对象。切记,字符串字面值与string是不同的类型。字符串字面值的类型实际上是由常量字符构成的数组。
所以前面我们看到的“aaa”并不是string类型,而是字符数组类型。如果要将“aaa”作为func函数参数,首先要进行第一步就是将字符串字面值转换为string对象。标准库允许把字符串字面值转换成string对象。
Demo demo("aaa"); //正确
所以上述代码是正确的。Demo类本身并没有接收字符串字面值的转换构造函数,但是有针对string的转换构造函数,所以这里面发生了一次隐式转换,将字符串字面值转换为string,然后调用string转换构造函数。
func(“aaa”); //报错
那为什么这里会报错,不是可以发生隐式转换吗?
这里报错涉及到编译器另外一条规则。
类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的隐式转换。如果同时提出多个转换请求,编译器会报错。
字符串字面量转换为string属于标准库的类类型转换,区别于普通变量类型转换。这里发生了两次转换,第一次是字符串字面值转换为string,第二次是string转换为Demo类型。因此报错。
func(string(“aaa”)); //可行
那为什么这条代码可以?
因为第一次的字符串字面值转换为string是显式转换,编译器只需要完成一次string转换为Demo类,没有超过一次。
文章评论