C++ Conversion Function(转换函数) and Explicit Keyword
0x01 Conversion Function
转换函数的目的就是将一个类的对象转换为另一种类型,比如说在数学的角度,一个分数可以转换为一个小数;那么从程序的角度来说,一个分数类(Fraction)的对象也可以转换为浮点数(double),此时就需要用到Conversion Fraction.
Fraction类的代码如下:
class Fraction
{
public:
Fraction(int num, int den = 1)
: numerator(num), denominator(den) {}
operator double() const {
return static_cast<double>(numerator) / denominator;
}
private:
int numerator; // 分子
int denominator; // 分母
};
上述程序的说明:
- 需要注意的是构造函数有两个形参,但最后一个形参有默认值,所以在定义对象的时候,可以只给一个参数,也可以给两个参数:
Fraction f1(5); // 正确 分字为5,分母为默认值1
Fraction f2(3, 5); // 正确 分字为3,分母为5
- 其中的
operator double() const{···}
就是转换函数,将Fraction对象转换为double,例如:
double d = f2 + 4; // 4.6
如果没有在类中定义转换函数,那么上述代码会报错,在定义了转换函数之后,f2
会转换为double
类型的0.6
和4
相加等到4.6后赋值给变量d
.
0x02 自动类型转换 (non-explicit ctor)
上面我们探讨了Fraction
转换为double
,其实反过来也是可以的,假设类的定义是下面这样的:
class Fraction
{
public:
Fraction(int num, int den = 1)
: numerator(num), denominator(den) {}
Fraction operator+(const Fraction& f) {
//do plus (加的动作这里没有详细设计)
...
return f;
}
private:
int numerator; // 分子
int denominator; // 分母
};
有如下的对象:
Fraction f(3, 5);
Fraction f2 = f + 4; // 首先调用(non-explicit)构造函数将4转换为Fraction
// 再调用operator+
此时就将4
转换为了Fraction
.
0x03 Conversion Function与non-explicit ctor共存时
假设当前类的定义为:
class Fraction
{
public:
Fraction(int num, int den = 1)
: numerator(num), denominator(den) {}
operator double() const {
return static_cast<double>(numerator) / denominator;
}
Fraction operator+(const Fraction& f) {
//do plus (加的动作这里没有详细设计)
...
return f;
}
private:
int numerator; // 分子
int denominator; // 分母
};
即Conversion Function
与non-explicit ctor
共存,此时下面的代码会产生歧义:
Fraction f(3, 5);
Fraction f2 = f + 4; // Error: ambiguous
因为对于代码Fraction f2 = f + 4;
会有两条可选路径:
- 第一种情况是将
4
转换为Fraction
,再调用operator+
; - 第二种情况是
f
转换为double
类型的0.6
,再将0.6
和4
相加之后得到4.6
,再调用non-explicit ctor
转换为Fraction
.
因为上述两种情况并不存在谁优于谁的情况,所以编译器也不知道调用哪个,所以会报错。
说明:
这里产生二义性并不是因为
Conversion Function
与non-explicit ctor
共存的原因,其产生的原因主要还是我们类的设计。
0x04 explicit keyword
当不允许发生隐式类型转换时,应该明确拒绝,即在构造函数之前加上 explicit
关键字:
class Fraction
{
public:
explicit Fraction(int num, int den = 1)
: numerator(num), denominator(den) {}
operator double() const {
return static_cast<double>(numerator) / denominator;
}
Fraction operator+(const Fraction& f) {
//do plus (加的动作这里没有详细设计)
...
return f;
}
private:
int numerator; // 分子
int denominator; // 分母
};
但是下面的代码依旧会出现问题,但是不再是二义性的问题了:
Fraction f(3, 5);
Fraction f2 = f + 4; // Error: conversion from 'double' to non-scalar type 'Fraction' requested
此时0x03
中的两种路径都行不通了:
- 因为构造函数有
explicit
修饰,所以4
不能再自动转换为Fraction
; - 虽然能够将
f
转换为double
类型的0.6
,再将0.6
和4
相加之后得到4.6
,同样因为构造函数有explicit
修饰,所以4.6
不能再自动转换为Fraction
。
所以会报错。