自定义类型转换


在〈运算符重载〉,若Rational加法的左运算数是int整数的话,运算符重载时使用了friend非成员函数,这明确地定义了遇到int为左运算数,而右运算数为Rational,计算结果要是Rational的话,应该采取的行为。

然而,在其他的运算需求中,可能会想要Rational能转换为intdouble或者是其他类型,以便进一步以该类型的其他值进行运算,这可以透过自定义转换函数来达到,又称为转型运算符。例如:

#include <iostream>
#include <string>
using namespace std;

struct Double {
    const double n;
    Double(double n) : n(n) {}
};

class Rational {
    int numer;
    int denom;

public:
    Rational(int numer, int denom) : numer(numer), denom(denom) {}

    operator double() {
        return static_cast<double>(this->numer) / this->denom;
    }

    operator Double() {
        return Double(static_cast<double>(this->numer) / this->denom);
    }
};

void foo(Double d) {
    cout << d.n << endl;
}

int main() {
    Rational a(1, 2);

    // a 隐含地转换为 double
    cout << a + 0.1 << endl;  
    cout << 0.3 + a << endl;

    // a 隐含地转换为 Double
    foo(a);

    return 0;
}

以上的范例,允许编译器隐含地完成类型转换,如果类型转换必须得明确,可以加上explicit,例如:

#include <iostream>
#include <string>
using namespace std;

struct Double {
    const double n;
    explicit Double(double n) : n(n) {}
};

class Rational {
    int numer;
    int denom;

public:
    Rational(int numer, int denom) : numer(numer), denom(denom) {}

    explicit operator double() {
        return static_cast<double>(this->numer) / this->denom;
    }

    explicit operator Double() {
        return Double(static_cast<double>(this->numer) / this->denom);
    }
};

void foo(Double d) {
    cout << d.n << endl;
}

int main() {
    Rational a(1, 2);

    cout << static_cast<double>(a) + 0.1 << endl;
    cout << 0.3 + static_cast<double>(a) << endl;

    foo(static_cast<Double>(a));

    return 0;
}

将范例中的static_cast拿掉,就会发生编译错误,因为explicit指出不允许隐含类型转换。


展开阅读全文