一、转换函数 Conversion Functions(operators)

在 C++ 中,使用类作为具体类型,对现实世界对象进行抽象。有时,需要隐式地将一种具体类型转换为另一种具体类型或 C++ 内建数据类型。转换函数在这种情况下发挥着重要作用。它类似于类中的运算符重载函数。

转换函数写法:operator typeName();

  • 转换函数必须是类的成员函数
  • 转换函数不能指定返回值类型
  • 转换函数不能有形参

例如下面的类:

class Fraction
{
public:
    Fraction(int numerator, int denominator = 1)
        :m_numerator(numerator), m_denominator(denominator)
    {
    }

    //转换函数
    operator double() const
    {
        return (double)m_numerator / m_denominator;
    }
private:
    int m_numerator;        //分子
    int m_denominator;      //分母
};

int main()
{
    Fraction f(8,5);
    double d = 4 + f;
    cout << d << endl;
    return 0;
}

输出:

5.6

注意: 编译器将在基于类型调用适当的功能时具有更多控制,而不是我们所期望的。所以使用类或对象的特定成员函数来执行此类转换才是良好的习惯。

二、构造函数隐式转换 non-explicit-one-argument constructor

class Fraction
{
public:
    Fraction(int numerator, int denominator = 1)
        :m_numerator(numerator), m_denominator(denominator)
    {
    }
    
    Fraction operator + (const Fraction& f) {
        return Fraction(m_numerator * f.m_denominator + f.m_numerator * m_denominator, m_denominator * f.m_denominator);
    }
    
    //转换函数
    operator string() const
    {   
        return to_string(m_numerator) + "/" + to_string(m_denominator);
    }
private:
    int m_numerator;        //分子
    int m_denominator;      //分母
};

int main()
{
    Fraction f(8,5);
    Fraction ff = f + 4; // 调用构造函数,将 4 转换成 Fraction(4, 1),然后再调用 operator +
    cout << (string)ff << endl;
    return 0;
}

输出:

28/5

三、转换函数与构造函数隐式转换(ambiguous)

class Fraction
{
public:
    Fraction(int numerator, int denominator = 1)
        :m_numerator(numerator), m_denominator(denominator)
    {
    }
    
    Fraction operator + (const Fraction& f) {
        return Fraction(m_numerator * f.m_denominator + f.m_numerator * m_denominator, m_denominator * f.m_denominator);
    }
    
    //转换函数
    operator double() const
    {
        return (double)m_numerator / m_denominator;
    }
    operator string() const
    {   
        return to_string(m_numerator) + "/" + to_string(m_denominator);
    }
private:
    int m_numerator;        //分子
    int m_denominator;      //分母
};

int main()
{
    Fraction f(8,5);
    Fraction ff = f + 4; // error: ambiguous overload for ‘operator+’ (operand types are ‘Fraction’ and ‘int’)
    cout << ff << endl;
    return 0;
}

输出:

main.cpp:54:21: error: ambiguous overload for ‘operator+’ (operand types are ‘Fraction’ and ‘int’)
   54 |     Fraction ff = f + 4;
      |                   ~ ^ ~
      |                   |   |
      |                   |   int
      |                   Fraction
main.cpp:54:21: note: candidate: ‘operator+(double, int)’ 
   54 |     Fraction ff = f + 4;
      |                   ~~^~~
main.cpp:21:14: note: candidate: ‘Fraction Fraction::operator+(const Fraction&)’
   21 |     Fraction operator + (const Fraction& f) {
      |              ^~~~~~~~
  • 可以将 4 隐式的转换为 Fraction 对象,然后调用 + 操作符重载
  • 也可以将 f 转换为 double,再与 4 相加,最后再将 double 隐式转换为 Fraction 对象

四、禁止构造函数隐式转换

class Fraction
{
public:
    explicit Fraction(int numerator, int denominator = 1)
        :m_numerator(numerator), m_denominator(denominator)
    {
    }
    
    Fraction operator + (const Fraction& f) {
        return Fraction(m_numerator * f.m_denominator + f.m_numerator * m_denominator, m_denominator * f.m_denominator);
    }
    
    //转换函数
    operator string() const
    {   
        return to_string(m_numerator) + "/" + to_string(m_denominator);
    }
    operator double() const
    {
        return (double)m_numerator / m_denominator;
    }
private:
    int m_numerator;        //分子
    int m_denominator;      //分母
};
int main()
{
    Fraction f(8,5);
    // Fraction ff = f + 4; // error: conversion from ‘double’ to non-scalar type ‘Fraction’ requested
    double ff = f + 4; // OK	5.6
    cout << ff << endl;
    return 0;
}
  • 由于在构造函数前面增加了 explicit 关键字,所以不能将 4 转换成 Fraction 类型;
  • 也不能先将 f 转换成 double 类型,与 4 相加,再将 double 隐式转换成 Fraction 类型,所以会报错。

参考:

  1. C++转换函数 (conversion function)与 C++中explicit关键字
  2. C++转换函数
  3. Conversion Operators in C++