带单一参数的构造函数在缺省情况下隐含一个转换操作符,请看下面的代码:class C {int i;//...public: C(int i);//constructor and implicit conversion operator//as well};void f() {C c(0);c = 5; //将 5 隐式转换为 C 对象,然后赋值}编译器重新编辑上述例子代码,如下: ////"c=5;" 被编译器转换成下面这个样子:/C temp(5);// 实例化一个临时对象,c = temp; // 用 = 赋值temp.C::~C(); // temp 的析构函数被激活在很多情况下,这个转换是有意的,并且是正当的。但有时我们不希望进行这种自动的转换,例如:class String {int size;char *p;//..public: String (int sz); //这里不希望进行隐式转换操作};void f (){ String s(10); // 下面是一个程序员的编码;发生一个意想不到的转换: s = 100; // 糟糕,100 被转换为一个 String,然后被赋值给 s} 为了避免这样的隐式转换,应该象下面这样显式声明该带单一参数的构造函数:class String {int size;char *p;//..public: // 不要隐式转换 explicit String (int sz); String (const char *s, int size n = 0); // 隐式转换};void f (){ String s(10); s = 100; // 现在编译时出错;需要显式转换: s = String(100); // 好;显式转换 s = "st"; // 好;此时允许隐式转换}
这个 《ANSI/ISO C++ Professional Programmer's Handbook 》是这样说的explicit ConstructorsA constructor that takes a single argument is, by default, an implicit conversion operator, which converts its argument toan object of its class (see also Chapter 3, "Operator Overloading"). Examine the following concrete example:class string{private:int size;int capacity;char *buff;public:string();string(int size); // constructor and implicit conversion operatorstring(const char *); // constructor and implicit conversion operator~string();};Class string has three constructors: a default constructor, a constructor that takes int, and a constructor thatconstructs a string from const char *. The second constructor is used to create an empty string object with aninitial preallocated buffer at the specified size. However, in the case of class string, the automatic conversion isdubious. Converting an int into a string object doesn't make sense, although this is exactly what this constructor does.Consider the following:int main(){string s = "hello"; //OK, convert a C-string into a string objectint ns = 0;s = 1; // 1 oops, programmer intended to write ns = 1,}In the expression s= 1;, the programmer simply mistyped the name of the variable ns, typing s instead. Normally,the compiler detects the incompatible types and issues an error message. However, before ruling it out, the compiler firstsearches for a user-defined conversion that allows this expression; indeed, it finds the constructor that takes int.Consequently, the compiler interprets the expression s= 1; as if the programmer had writtens = string(1);You might encounter a similar problem when calling a function that takes a string argument. The following examplecan either be a cryptic coding style or simply a programmer's typographical error. However, due to the implicitconversion constructor of class string, it will pass unnoticed:int f(string s);int main(){f(1); // without a an explicit constructor,//this call is expanded into: f ( string(1) );//was that intentional or merely a programmer's typo?}'In order to avoid such implicit conversions, a constructor that takes one argument needs to be declared explicit:class string{//...public:explicit string(int size); // block implicit conversionstring(const char *); //implicit conversion~string();};An explicit constructor does not behave as an implicit conversion operator, which enables the compiler to catch thetypographical error this time:int main(){string s = "hello"; //OK, convert a C-string into a string objectint ns = 0;s = 1; // compile time error ; this time the compiler catches the typo}Why aren't all constructors automatically declared explicit? Under some conditions, the automatic type conversion isuseful and well behaved. A good example of this is the third constructor of string:string(const char *);The implicit type conversion of const char * to a string object enables its users to write the following:string s;s = "Hello";The compiler implicitly transforms this intostring s;//pseudo C++ code:s = string ("Hello"); //create a temporary and assign it to sOn the other hand, if you declare this constructor explicit, you have to use explicit type conversion:class string{//...public:explicit string(const char *);};int main(){string s;s = string("Hello"); //explicit conversion now requiredreturn 0;}Extensive amounts of legacy C++ code rely on the implicit conversion of constructors. The C++ Standardizationcommittee was aware of that. In order to not make existing code break, the implicit conversion was retained. However, anew keyword, explicit, was introduced to the languageto enable the programmer to block the implicit conversionwhen it is undesirable. As a rule, a constructor that can be invoked with a single argument needs to be declaredexplicit. When the implicit type conversion is intentional and well behaved, the constructor can be used as animplicit conversion operator.
