类型转换操作符operator type(),是不同于重载()操作符operator()()的,更不同于类构造函数 classname()
类型转换操作符(type conversion operator)是一种特殊的类成员函数,它定义将类类型值转变为其他类型值的转换。转换操作符在类定义体内声明,在保留字 operator 之后跟着转换的目标类型。boost::ref和boost::cref就使用到了类型转换操作符。
函数原型
T1:: operator T2() const ; // T1的成员函数,"(T2)a"类型转换 1. 转换函数必须是成员函数,不能指定返回类型,并且形参表必须为空;返回值是隐含的,返回值是与转换的类型相同的,即为上面原型中的T2;
2. T2表示内置类型名(built-in type)、类类型名(class type)或由类型别名(typedef)定义的名字;对任何可作为函数返回类型的类型(除了 void 之外)都可以定义转换函数,一般而言,不允许转换为数组或函数类型,转换为指针类型(数据和函数指针)以及引用类型是可以的;
3. 转换函数一般不应该改变被转换的对象,因此转换操作符通常应定义为 const 成员;
4. 支持继承,可以为虚函数;
5. 只要存在转换,编译器将在可以使用内置转换的地方自动调用它;
for an example: #include < iostream > using namespace std; class D{ public : D( double d): d_(d){} operator int () const { cout << " (int)d called!! " << endl; return static_cast < int > (d_); } private : double d_; }; int add( int a, int b){ return a + b; } int main(){ D d1 = 1.1 ; D d2 = 2.2 ; cout << " add(d1,d2)= " << add(d1,d2) << endl; return 0 ; } (int)d called!! (int)d called!! add(d1,d2)=3 Press any key to continue 类型转换构造函数(conversion constructor)先来说下类型转换构造函数:C++中的explicit用来修饰类的构造函数,表明该构造函数是显示的,既然有显示的,那么就有隐式的
若果一个类的构造函数时一个单自变量的构造函数,所谓的单自变量是可能声明一个单一参数,也可能声明一个拥有多个参数,并且除了第一参数外都其他参数都有默认值
这样的constructor称为单自变量constructor.
若果类中有这样一个constructor那么在编译的时候编译器将会产生一个省却的操作:将该constructor参数对应 的 数据类型 的 数据转换为该类的对象
class MyClass { public: MyClass( int num ); } .... MyClass obj = 10; //ok,convert int to MyClass 在上面的操作中编译器其实产生代码如下:
Myclass temp(10);
Myclass obj=temp;
若果要避免编译器产生上诉的隐式转换,那么此时explicit将产生作用。
explicit的作用:
explicit关键字将作用在类的构造函数,被修饰的构造函数,将再不能发生隐式转换了,只能以显示的进行类型转换
explicit 的注意:
只能作用在类的内部的构造函数上
只能作用在单自变量的构造函数上
class Circle { public : Circle( double r) : R(r) {} Circle( int x, int y = 0 ) : X(x), Y(y) {} Circle( const Circle & c) : R(c.R), X(c.X), Y(c.Y) {} private : double R; int X; int Y; }; int main(){ Circle A = 1.23 ; // 发生隐式类型转换 // 编译器会将它变成如下代码 // tmp = Circle(1.23) // Circle A(tmp); // tmp.~Circle(); Circle B = 123 ; // 注意是int型的,调用的是Circle(int x, int y = 0) // 它虽然有2个参数,但后一个有默认值,任然能发生隐式转换 Circle C = A; // 这个算隐式调用了拷贝构造函数 return 0 ; }
加了explicit关键字后,可防止以上隐式类型转换发生
class Circle { public : explicit Circle( double r) : R(r) {} explicit Circle( int x, int y = 0 ) : X(x), Y(y) {} explicit Circle( const Circle & c) : R(c.R), X(c.X), Y(c.Y) {} private : double R; int X; int Y; }; int _main() { // 一下3句,都会报错 // Circle A = 1.23; // Circle B = 123; // Circle C = A; // 只能用显示的方式调用了 // 未给拷贝构造函数加explicit之前可以这样 Circle A = Circle( 1.23 ); Circle B = Circle( 123 ); Circle C = A; // 给拷贝构造函数加了explicit后只能这样了 Circle A( 1.23 ); Circle B( 123 ); Circle C(A); return 0 ; }
类型转换操作符 vs 类型转换构造函数(conversion constructor) 有时候使用conversion constructor就能实现类型转换,这种方式效率更高而且也更直观,下面举例说明:
1 #include < iostream > 2 using namespace std; 3 class A{ 4 public : 5 A( int num = 0 ) 6 :dat(num){ 7 cout << " A单参数构造函数called!! " << endl; 8 } 9 operator int (){ 10 cout << " A::operator int() called!! " << endl; 11 return dat; 12 } 13 private : 14 int dat; 15 }; 16 17 class X{ 18 public : 19 X( int num = 0 ) 20 :dat(num){ 21 cout << " X单参数构造函数called!! " << endl; 22 } 23 operator int (){ 24 cout << " X::operator int() called!! " << endl; 25 return dat; 26 } 27 operator A(){ 28 cout << " operator x() called!! " << endl; 29 A temp = dat; 30 return temp; 31 } 32 private : 33 int dat; 34 }; 35 36 int main(){ 37 cout << " ///trace more/// " << endl; 38 A more = 0 ; 39 40 cout << " ///trace stuff/// " << endl; 41 X stuff = 2 ; 42 43 cout << " //trace hold dingyi// " << endl; 44 int hold; 45 46 cout << " ///trace hold=stuff// " << endl; 47 hold = stuff; 48 cout << " ///two trace hold=stuff// " << endl; 49 cout << " hold: " << hold << endl; 50 51 cout << " //trace more=stuff// " << endl; 52 more = stuff; 53 cout << " //two trace more=stuff// " << endl; 54 cout << " more: " << more << endl; 55 56 return 0 ; 57 } ![](http://static.oschina.net/uploads/img/201512/27153217_jiAH.jpg)
上面这个程序中X类通过“operator A()”类型转换来实现将X类型对象转换成A类型,这种方式需要先创建一个临时A对象再用它去赋值目标对象;更好的方式是为A类增加一个构造函数:
A( const X & rhs) : dat(rhs) {} 同时,请注意上面程序的more的类型在调用std::cout时被隐式地转成了int!
一个简单boost::ref实现
通过重载type conversion operator,我们就可以自己实现一个简版的boost::ref。
1 #include < iostream > 2 3 template < class T > 4 class RefHolder{ 5 public : 6 RefHolder(T & ref ) : ref_( ref ) {} 7 8 /* “(T&)A”类型转换操作符 */ 9 operator T & () const { 10 return ref_; 11 } 12 private : 13 T & ref_; 14 }; 15 16 17 template < class T > 18 inline RefHolder < T > ByRef(T & t) { 19 return RefHolder < T > (t); 20 } 21 22 int inc( int & num) { 23 num ++ ; 24 return num; 25 } 26 27 28 int main() { 29 int n = 1 ; 30 std::cout << inc(ByRef(n)) << std::endl; // RefHolder<int>被转换成了"int&"类型 31 32 return 0 ; 33 } 34 35