類型轉換操做符operator type(),是不一樣於重載()操做符operator()()的,更不一樣於類構造函數 classname() ios
類型轉換操做符(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 以外)均可以定義轉換函數,通常而言,不容許轉換爲數組或函數類型,轉換爲指針類型(數據和函數指針)以及引用類型是能夠的; ui
3. 轉換函數通常不該該改變被轉換的對象,所以轉換操做符一般應定義爲 const 成員; spa
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 的注意:
只能做用在類的內部的構造函數上
只能做用在單自變量的構造函數上
ci
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