#include <iostream>
using namespace std;
class square
{
private:
int a;
public:
explicit square(int x):a(x) {};
bool compare(square S);
};
bool square::compare(square S)
{
return a*a > (S.a)*(S.a) ? 1:0;
}
int main()
{
square t(1);
cout << t.compare(-4) << endl;
}
上面程序中,compare其实是比较两个数平方的大小,compare需要传递的参数是square类,所以虽然传递的参数是-4,但系统会自动调用构造函数square(-4),将-4转换为square类,即S.a = -4。然后再进行平方比较,而显然1^2 < (-4)^2,所以程序输出0。
但此时问题来了,如果使用者对compare函数不了解,以为传递的参数就是需要比较的数,即compare是比较对象1^2与-4的大小,此时程序输出0,使用者一定会莫名其妙。这就显示出explicit的用处了。
将程序第10行修改为:
explicit square(int x):a(x) {};
此时再编译,会提示错误:
error C2664: “square::compare”:不能将参数1 从“int”转换为“square”
这样就可以避免因为不理解函数而造成的错误,编译器不会把声明为explicit的构造函数用于隐式类型转换,它只能在程序代码中显式创建对象。因为根据定义,隐式的类型转换是把给定的类型转换为另一种类型,对只有一个参数的构造函数,只需使用explicit关键字,就可避免进行隐式类型转换。
既然explicit那么有用,为什么不在所有的构造函数前都自动加上explicit关键字呢?
依然使用上面的程序(不加explicit),
但我们在定义square对象时,可能会这样定义:
square s = 1;
编译时,不会发生错误,因为系统自动调用构造函数,这会给我们带来很大方便。如果第10行依然修改为:
explicit square(int x):a(x) {};
此时我们初始化对象只能用 square t(1); 这种方式。
这个例子可能不够典型,大家记得string类吧。
我们经常这样定义:
string s = “Helloworld!”;
这是因为string类有一个构造函数,自动将char*转换为string类,所以我们才可以这样使用,如果给这个构造函数加上explicit的话,我们只能这样定义:
string s(“Helloworld!”);
这样对于熟悉C语言的人会造成很大的不便。