Программирование >>  Инициализация объектов класса, структура 

1 ... 247 248 249 [ 250 ] 251 252 253 ... 395


class Number {

public:

operator float(); operator int();

...

Number num;

таких последовательностей? Или какую-то из них можно нредночесть остальным?

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

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

1. operator float() -> точное соответствие

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

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

Token::operator float() .

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

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

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

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

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

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

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

В классе разрешается определять много конвертеров. Например, в нашем классе Number их два: operator int() и operator float() , причем оба способны преобразовать объект типа Number в значение типа float. Естественно, можно воспользоваться конвертером Token::operator float() для прямой трансформации. Но и Token::operator int() тоже подходит, так как результат его применения имеет тип int и, следовательно, может быть преобразован в тин 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. Таким образом, имеются две последовательности определенных пользователем преобразований:

1. точное соответствие -> SmiallInt( double )

2. стандартное преобразование -> SmiallInt( int )

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

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

class Number {

public:

operator float(); operator int();

...

классе Number есть два конвертера:

то невозможно неявно преобразовать объект типа Number в тип long. Следующая инструкция вызывает ошибку компиляции, так как выбор последовательности

ошибка: можно применить как float(), так и int()

определенных пользователем преобразований неоднозначен:

long lval = num;

Для трансформации num в значение типа long применима: две такие последовательности:

1. operator float() -> стандартное преобразование

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



правильно: явное приведение типа С помощью явного приведения типов программист способен задать нужное изменение:

long lval = static cast< int >( num );

Вследствие такого указания выбирается конвертер Token::operator int() , за которым следует стандартное преобразование в long.

Неоднозначность при выборе последовательности трансформаций может возникнуть и

class SmallInt { public:

SmallInt( const Number s );

...

class Number { public:

operator SmallInt();

...

extern void compute( SmallInt ); extern Number num;

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

compute( num ); ошибка: возможно два преобразования

Аргумент num преобразуется в тин SmallInt двумя разными способами: с помощью конструктора SmallInt::SmallInt(const Numbers) либо с помощью конвертера Number::operator SmallInt() . Поскольку оба изменения одинаково хороши, вызов считается ошибкой.

Для разрешения неоднозначности программист может явно вызвать конвертер класса

правильно: явный вызов устраняет неоднозначность Number:

compute( num.operator SmallInt() );

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

compute( SmallInt( num ) ); ошибка: по-прежнему неоднозначно

Как видите, наличие большого числа подобных конвертеров и конструкторов небезопасно, поэтому их. следует применять с осторожностью. Ограничить

Поскольку в обоих случаях за использованием конвертера следует применение стандартного преобразования, то обе последовательности одинаково хороши и компилятор не может выбрать ни одну из них.



1 ... 247 248 249 [ 250 ] 251 252 253 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика