类型转换操作符(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