Ambiguities between Conversions

An ambiguity can arise when two classes define the same conversion. For example:

class FixedPoint;

class Fraction

{

public:

Fraction( FixedPoint value ); // FixedPoint -> Fraction

};

class FixedPoint

{

public:

operator Fraction(); // FixedPoint -> Fraction

};

void main()

{

Fraction a;

FixedPoint b;

a = b; // Error; ambiguous

// a = Fraction( b );

// a = b.operator Fraction();

}

The compiler cannot choose between the constructor and the conversion operator. You can explicitly specify the conversion operator, but not the constructor:

a = b.operator Fraction(); // Call conversion operator

a = Fraction( b ); // Error: still ambiguous

a = (Fraction)b; // Error: still ambiguous

This type of ambiguity is easy to avoid, since it occurs only when the classes know of each other, which means that they were written by the same programmer(s). If you simply remove one of the conversion functions, the problem does not arise.

Ambiguities can also arise when multiple classes define similar implicit conversions. For example, suppose you have the Fraction class and some associated functions that use Fraction objects, as follows:

class Fraction

{

public:

Fraction( float value ); // float -> Fraction

};

void calc( Fraction parm );

You might also have a FixedPoint class that includes a similar set of associated functions:

class FixedPoint

{

public:

FixedPoint( float value ); // float -> FixedPoint

};

void calc( FixedPoint parm );

Now consider what happens if you try to use both the Fraction and the FixedPoint classes in the same program:

void main()

{

calc( 12.34 ); // Error: ambiguous

// calc( Fraction( 12.34 ) );

// calc( FixedPoint( 12.34 ) );

}

The compiler cannot choose which conversion to apply when calling the calc function. This type of ambiguity is difficult to avoid, because it can occur even if Fraction and FixedPoint are written by different programmers. Neither programmer would have noticed the problem because it doesn't appear when either class is used by itself; the ambiguity arises only when they are used together. This problem can be solved if the user of the classes explicitly specifies a conversion by using the constructor for the class desired.

It is difficult to anticipate all possible ambiguities that may involve your class. When you write a class, you might define only a small number of conversions. However, when other programmers write their classes, they can also define conversions involving your class. They can define constructors that convert an object of your class into one of theirs, or they can define conversion operators that turn an object of their class into one of yours.

To reduce the likelihood of ambiguities, you should define implicit conversions for your classes only when there is a clear need for them. You can always perform conversions explicitly by using constructors that require more than one argument, or by using ordinary member functions to perform conversions (for example, cvtToOtherType).

See the C++ Language Reference for a complete description of the rules governing conversions.