類型轉換操作符(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 }

上面這個程序中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