extern void func( Number );

SmallInt si(87);

int main()

{ // ошибка: не существует неявного преобразования из SmallInt в Number

func( si );

// ...

}

Однако такой конструктор все же можно использовать для преобразования типов, если оно запрошено явно в форме оператора приведения типа:

SmallInt si(87);

int main()

{ // ошибка: не существует неявного преобразования из SmallInt в Number

func( si );

func( Number( si ) ); // правильно: приведение типа

func( static_cast Number ( si ) ); // правильно: приведение типа

}

<p>15.10. Выбор преобразования A</p>

Определенное пользователем преобразование реализуется в виде конвертера или конструктора. Как уже было сказано, после преобразования, выполненного конвертером, разрешается использовать стандартное преобразование для приведения возвращенного значения к целевому типу. Трансформации, выполненной конструктором, также может предшествовать стандартное преобразование для приведения типа аргумента к типу формального параметра конструктора.

Последовательность определенных пользователем преобразований – это комбинация определенного пользователем и стандартного преобразования, которая необходима для приведения значения к целевому типу. Такая последовательность имеет вид:

Последовательность стандартных преобразований -

Определенное пользователем преобразование -

Последовательность стандартных преобразований

где определенное пользователем преобразование реализуется конвертером либо конструктором.

Не исключено, что для трансформации исходного значения в целевой тип существует две разных последовательности пользовательских преобразований, и тогда компилятор должен выбрать из них лучшую. Рассмотрим, как это делается.

В классе разрешается определять много конвертеров. Например, в нашем классе Number их два: operator int() и operator float(), причем оба способны преобразовать объект типа Number в значение типа float. Естественно, можно воспользоваться конвертером Token::operator float() для прямой трансформации. Но и Token::operator int() тоже подходит, так как результат его применения имеет тип int и, следовательно, может быть преобразован в тип float с помощью стандартного преобразования. Является ли трансформация неоднозначной, если имеется несколько таких последовательностей? Или какую-то из них можно предпочесть остальным?

class Number {

public:

operator float();

operator int();

// ...

};

Number num;

float ff = num; // какой конвертер? operator float()

* В таких случаях выбор наилучшей последовательности определенных пользователем преобразований основан на анализе последовательности преобразований, которая применяется после конвертера. В предыдущем примере можно применить такие две последовательности: operator float() - точное соответствие

* operator int() - стандартное преобразование

Как было сказано в разделе 9.3, точное соответствие лучше стандартного преобразования. Поэтому первая последовательность лучше второй, а значит, выбирается конвертер Token::operator float().

Может случиться так, что для преобразования значения в целевой тип применимы два разных конструктора. В этом случае анализируется последовательность стандартных преобразований, предшествующая вызову конструктора:

class SmallInt {

public:

SmallInt( int ival ) : value( ival ) { }

SmallInt( double dval )

: value( static_cast int ( dval ) );

{ }

};

extern void manip( const SmallInt & );

int main() {

double dobj;

manip( dobj ); // правильно: SmallInt( double )

}

* Здесь в классе SmallInt определено два конструктора – SmallInt(int) и SmallInt(double), которые можно использовать для изменения значения типа double в объект типа SmallInt: SmallInt(double) трансформирует double в SmallInt напрямую, а SmallInt(int) работает с результатом стандартного преобразования double в int. Таким образом, имеются две последовательности определенных пользователем преобразований: точное соответствие - SmallInt( double )

* стандартное преобразование - SmallInt( int )

Поскольку точное соответствие лучше стандартного преобразования, то выбирается конструктор SmallInt(double).

Перейти на страницу:

Похожие книги