本文主要参考《C++ Primer 4e》第12.4.4小节,以及《Effective C++ 3e》第0章。
这里定义了三个构造函数,后面的两个构造函数都定义了一个隐式转化。因此,在期待一个Sales_item类型对象的地方,可以使用一个string或一个istream:
same_isbn期待一个Sales_item对象,于是编译器在此处接受一个string对象null_book,并调用Sales_item(const std::string &book)生成一个新的Sales_item对象,该新对象被传递给same_isbn。
这段代码将cin隐式转化为Sales_item对象。
这些行为在多数情况下都不是我们想要的,如何抑制这种情况?
可以通过将构造函数声明为explicit,来防止在需要隐式转化的上下文使用构造函数:
explicit关键字只能用于类内部的构造函数声明上,在类的定义体外部所做的定义上不再重复它:
通常,除非有明显的理由想要定义隐式转化,否则,单形参构造函数应该为explicit。将构造函数设置为explicit可以避免错误,并且当转换用用时,用户可以显式地构造对象。
可以用单个实参来调用的构造函数定义了从形参类型到该类型的一个隐式转换。这句话有点绕,我们来看一个例子。
class Sales_item {
public:
Sales_item() : units_sold(0), revenue(0.0) {}
// default argument for book is the empty strings
Sales_item(const std::string &book = "") :
isbn(book), units_sold(0), revenue(0.0) {}
Sales_item(std::istream &is);
bool same_isbn(const Sales_item &rhs) const
{ return isbn == rhs.isbn; }
private:
std::string isbn;
unsigned units_sold;
double revenue;
};
这里定义了三个构造函数,后面的两个构造函数都定义了一个隐式转化。因此,在期待一个Sales_item类型对象的地方,可以使用一个string或一个istream:
Sales_item item;
string null_book = "9-999-99999-9";
// ok: builds a Sales_item with 0 units_sold and revenue from
// and isbn equal to null_book
item.same_isbn(null_book);
same_isbn期待一个Sales_item对象,于是编译器在此处接受一个string对象null_book,并调用Sales_item(const std::string &book)生成一个新的Sales_item对象,该新对象被传递给same_isbn。
更成问题的是从istream到Sales_item的隐式转化:
// ok: uses the Sales_item istream constructor to build an object
// to pass to same_isbn
item.same_isbn(cin);
这段代码将cin隐式转化为Sales_item对象。
这些行为在多数情况下都不是我们想要的,如何抑制这种情况?
可以通过将构造函数声明为explicit,来防止在需要隐式转化的上下文使用构造函数:
class Sales_item {
public:
Sales_item() : units_sold(0), revenue(0.0) {}
// default argument for book is the empty strings
explicit Sales_item(const std::string &book = "") :
isbn(book), units_sold(0), revenue(0.0) {}
explicit Sales_item(std::istream &is);
bool same_isbn(const Sales_item &rhs) const
{ return isbn == rhs.isbn; }
private:
std::string isbn;
unsigned units_sold;
double revenue;
};
explicit关键字只能用于类内部的构造函数声明上,在类的定义体外部所做的定义上不再重复它:
// error: explicit allowed only on constructor declaration in class header
explicit Sales_item::Sales_item(istream &is)
{
is >> *this; // use Sales_item input operator to read the members
}
通常,除非有明显的理由想要定义隐式转化,否则,单形参构造函数应该为explicit。将构造函数设置为explicit可以避免错误,并且当转换用用时,用户可以显式地构造对象。