《C++ Primer》中提到:
“可以用 单个形参来调用 的构造函数定义了从 形参类型 到 该类类型 的一个隐式转换。”
注意, “可以用单个形参进行调用” 并不是指构造函数只能有一个形参,而是它可以有多个形参,但那些形参都是有默认实参的。
那么,什么是“隐式转换”呢? 从 构造函数形参类型 到 该类类型 的一个编译器的自动转换。
通过下面代码来看一看:
#include <string>
#include <iostream>
using namespace std;
class BOOK //定义了一个书类
{
private:
string _bookISBN; //书的ISBN号
float _price; //书的价格
public:
//定义了一个成员函数,这个函数是“实参为类类型的函数”
//这个函数用于比较两本书的ISBN号是否相同
bool isSameISBN(const BOOK & other) {
return other._bookISBN == _bookISBN;
}
//类的构造函数 “传一个参数就可以进行调用的构造函数”(虽然它有两个形参,但其中一个有默认实参,只用一个参数也能进行调用)
BOOK(string ISBN, float price = 0.0f) :_bookISBN(ISBN), _price(price) {}
};
int main()
{
BOOK A("A-A-A"); //生命周期是整个main函数
BOOK B("B-B-B");
BOOK("C-C-C"); //匿名对象,生命周期在这一行
cout << A.isSameISBN(B) << endl; //正常调用函数,无需发生转换
cout << A.isSameISBN(string("A-A-A")) << endl; //此处即发生一个隐式转换:string类型-->BOOK类型,借助BOOK的构造函数进行转换,以满足isSameISBN函数的传参要求。
cout << A.isSameISBN(BOOK("A-A-A")) << endl; //显式创建匿名临时对象,也即是编译器干的事情。
system("pause");
}
通过代码可以看到,isSameISBN函数需要BOOK类类型的形参,但传递的参数是string类型。但是,BOOK类中有个构造函数,它使用一个string类型实参进行调用,编译器调用了这个构造函数,隐式地将stirng类型转换为BOOK类型(构造了一个BOOK临时对象),再传递给isSameISBN函数。
隐式类类型转换还是会带来风险的,隐式转换得到类的临时变量,完成操作后就消失了,我们构造了一个完成测试后被丢弃的对象。
我们可以通过explicit
声明来抑制这种转换:
explicit BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}
explicit
关键字修饰构造函数。会禁止单参构造函数的隐式类型转换。
BOOK类构造函数就不能用于隐式地创造对象。