编译器经常会背着我们做一些我们不希望发生的事情,最典型的是隐式转换。不过庆幸的是,编译器只会帮助我们进行一次转换,而不会无休止的隐式转换,直至满足条件为止。例如,下面先定义一个Array模板类:
template<class T>class Array {
public:
Array(int lowBound,int highBound);
Array(int size);
T& operator[](int index);
bool operator==(const Array<int>& lhs,const Array<int>& rhs);
};
而在使用中,
Array<int> a[10];
Array<init>b[10];
for(int i=0;i<10;i++) {
if(a==b[i]) {
//发生点什么
}
}
由于书写错误,本来是a[i]==b[i],而出现了上面的a==b[i]。但是编译器并不会报错,由于在Array模板类中有重载了==操作符,而且参数都为Array数组。在Array的构造函数中存在只有一个int类型的构造函数,因此编译器会根据b[i],帮我们产生一个临时Array对象,然后调用==操作赋函数。 编译器没有报错,而出现这种情况,可以将构造函数添加一个声明:explicit。这样子编译器便不能因隐式类型转换的需要而调用它们。编译器调用构造函数帮我们产生需要的对象,但是它只会产生一次,而不会在临时对象的基础在调用构造函数产生需要的对象。例如:
template<class T>class Array {
public:
class ArraySize {
public:
ArraySize(int numElements):theSize(numElements) {}
int size() const {return theSize;}
private:
int theSize;
};
Array(int lowBound,int highBound);
Array(ArraySize size);
T& operator[](int index);
bool operator==(const Array<int>& lhs,const Array<int>& rhs);
};
同样在使用中出现前面的错误,即
Array<int> a[10];Array<init>b[10];
for(int i=0;i<10;i++) {
if(a==b[i]) {//原意是a[i],现在出现了错误
//发生点什么
}
}
编译器需要一个Array<int>的对象在==的右手边,得以针对Array<int>对象调用operator==,但是此刻并没有“但一自变量,类型为int”的构造函数。同时,编译器不会考虑将int转换为一个临时性的ArraySize对象(这是可行的),然后在根据这个临时对象产生必要的Array<int>对象。即编译器需要需要做两件事情:1.将int转换为ArraySize类型临时对象;2.再将ArraySize临时对象转换为Array<int>对象。然后编译器不会这么做,而会对上面的代码发错错误消息。幸好编译器不会做这种事情,否则我们的程序不知道会出现多少潜在的错误。不管怎么样,隐式转换总是会带来隐患。需要小心谨慎!