作者 | 梁唐
大家好,我是梁唐。
这是EasyC++系列的第69篇,来聊聊转换函数。
上一篇我们聊了类的转换,C++允许通过构造函数进行隐式类型转换。
那我们自然而然产生一个问题:这样的转换可逆吗?我们有没有办法把一个类的对象再转换回基本变量类型呢?
比如:
Time t(14);
int x = t;
这是可以的,不过不是使用构造函数。构造函数只能用于从某种类型到类类型的转换,要进行相反的转换需要使用C++中的一种特殊运算符函数——转换函数。
转换函数是用户定义的强制类型转换,可以使用强制类型转换的语法来使用。加入我们定义了Time
类的转换函数,我们可以使用如下的转换:
Time t(14);
int x = int(t);
int y = (int) t;
那么如何创建转换函数呢?其实转换函数本质上也是一种运算符重载,要转换为typeName
类型,需要使用这种形式的转换函数:
operator typeName();
并且还有几个条件:
加上转换类型之后,Time
定义如下:
class Time {
private:
int minutes;
public:
Time();
Time(int m) {
minutes = m;
}
operator int() const;
operator double() const;
};
虽然转换函数没有声明返回类型,但是我们一样需要返回所需的值。我们再来看下实现的代码:
Time::operator int() const {
return minutes;
}
Time::operator double() const {
return double(minutes);
}
到这里还没有结束,还有一个很有趣的问题,假设我们使用cout
来输出Time
对象,那么请问输出的结果会是int
还是double
呢?
Time t(14);
cout << t << endl;
答案是都不会,编译器会报错。因为cout
时没有指定类型,所以编译器会报错使用了二义性(ambiguous)转换。但如果我们去掉一个转换函数,只保留一个,则不会有二义性,可以运行。
同样,我们在赋值的时候也会存在二义性:
long t = Time(14);
解决办法是在赋值的时候使用枪支类型转换来指出要使用哪个转换函数:
Time t(14);
int x = (int) t;
int y = double(t);
和类的转换一样,转换函数有的时候也会有意外情况。为了避免在我们意料之外进行转换,C++11对转换函数也支持了explicit
关键字,加上了关键字之后,只有强制转换时才会调用这些转换函数。
class Time {
private:
int minutes;
public:
Time();
Time(int m) {
minutes = m;
}
explicit operator int() const;
explicit operator double() const;
};