19.9.1.  Conversion Operators

[ fromfile: useroperators.xml id: conversionoperators ]

You saw earlier in Section 2.12 that you can introduce type conversions into the compiler's type system through the use of conversion constructors. This makes it possible to convert from an already existing type to a new type. To define a conversion in the opposite direction, a conversion operator is needed. In Section 5.3, you saw how to define the behavior of operators on nonsimple types. A conversion operator uses the same mechanism to overload a typecast.

A conversion operator looks quite different from other member functions. It has no return type (not even void) and no parameters. When a conversion operator is applied, it returns an object of its named type: a conversion of the host object as specified in the function body. Conversion operators are generally intended for implicit use so that automatic conversions can be made as needed (e.g., when function calls are being resolved as you saw in Section 5.1).

When the program in Example 19.13 is run, you can see the use of user-defined conversions from Fraction to double and to QString.

Example 19.13. src/operators/fraction/fraction-operators.cpp

#include <QString>
#include <QTextStream>

QTextStream cout(stdout);

class Fraction {
public:
    Fraction(int n, int d = 1)          1 
        : m_Numerator(n), m_Denominator(d) {}

    operator double() const {           2
        return (double) m_Numerator / m_Denominator;
    }  
    
    operator QString () const {
        return  QString("%1/%2").arg(m_Numerator).arg(m_Denominator);
    }
private:
    int m_Numerator, m_Denominator;
};

QTextStream& operator<< (QTextStream& os, const Fraction& f) {
    os << static_cast<QString> (f);     3
    return os;
}

int main() {
    
    Fraction frac(1,3);
    Fraction frac2(4);                  4
    double d = frac;                    5
    QString fs = frac;                  6
    cout << "fs= " << fs << "  d=" << d << endl;
    cout << frac << endl;               7
    cout << frac2 << endl;
    return 0;
}

1

Conversion constructor.

2

Conversion operator.

3

Explicit cast calls conversion operator.

4

Conversion constructor call.

5

Calls conversion operator.

6

Another conversion operator call.

7

Operator<<() called directly.


Here is the output of this program.

 src/operators/fraction> ./fraction
 fs= 1/3  d=0.333333
 1/3
 4/1
 src/operators/fraction>