FreeOZ论坛
标题:
再说C++的类型转换:隐式转换
[打印本页]
作者:
key
时间:
11-5-2009 22:08
标题:
再说C++的类型转换:隐式转换
在 Effictive C++ 第45条款中说:清楚知道C++译译器为我们完成和调用哪些函数。
这个主题是很好的,可惜里面说到的内容又是翻来覆去说copy constructor之类的东西。
我觉得C++编译器偷偷摸摸搞的小动作中,隐式转换是最可怕的。
先看下面的程序段:
template<class T> class X { public: X(double x) {} };
void foo(X<int> const & x) { cout << "foo" << endl; }
int main() { foo(1.5); return 0; }
复制代码
事实上这个程序是可以成功编译并运行的。需要foo()并没有定义参数为double的函数,但因为X<T>包含了参数为double的构造函数,
所以上面的例子中,foo(1.5)的执行流程是:
1.5 -> X<int>临时对象 -> foo(X<int> const &)执行
注意,由于C++明确禁止把无名临时变量用做非const引用参数,所以,如果定义为:
void foo(X<int> &x) { ... }
复制代码
由程序编译不成功。
对于要执行的任意函数foo(x),编译器会试图找到完全匹配的函数声明。如果找不到,编译器会试图通过在实参上进行隐式转换来找到合适
的函数
。上面的例子中,编译器没有找到foo(double)这样的函数定义,但找到了一个同名的函数foo(X<int> const&),而且能找到
double -> X的转换(通过X<T>::X(double)这个构造函数),于是就执行了隐式转换。
这种转换能带来方便,但同时也带来了问题。如果你另外有:
void foo(X<string> &x) { ... }
那么编译器就罢工了,因为会出现ambiguity,编译器不知道你想要哪一个。
反向隐式转换也是可能的:
template<class T> class X {
public:
operator double();
};
void foo(double v);
int main() {
X x;
foo(x);
return 0;
}
复制代码
这种情况下,x会隐式转换成double,然后再进行函数调用。考虑下面的情况:
template<class T> class X {
public:
operator double();
operator char *();
};
int main()
{
cout << X << endl;
}
复制代码
这种情况下编译器会因为ambiguous而罢工,因为他试图把X转成合适的类型时发现了double和char*两种类型,
结果不知所措了。
在可能的情况可,我们最好能把隐式转换显式化,也就是说,把变量变成最终的形式,而不是等待编译器也帮我们
转换。
隐式转换同样也影响着类的操作符重载。在通常情况下,我们在实现类的操作符重载时,可以选持成员函数和非成员
函数两种方式。如果选择为成员函数,则可以显式的禁止隐式转换。比如:
template<class T> class X {
public:
X(double d);
~X();
X const & operator += (X const &);
};
template<class T> class Y {
public:
Y(double d);
~Y();
friend Y const & operator += (Y const &);
}
复制代码
对于X<int> x; Y<int> y;double d = 1.0来说 d+= x; 是不成立的,而 d += y;则成立,但操作后左式的值没有改变,
显然,我们不希望有这种bug出现在程序中。但对于非赋值的二元操作符重载来说,我们一般希望对称的表达式,所以一般建议
是允许隐式转换,即不采用成员函数的方式来设定操作符重载。
参考:
* C++编译惯用法,2.4
欢迎光临 FreeOZ论坛 (https://www.freeoz.org/bbs/)
Powered by Discuz! X3.2