|
Программирование >> Инициализация объектов класса, структура
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 ) ); ошибка: по-прежнему неоднозначно Как видите, наличие большого числа подобных конвертеров и конструкторов небезопасно, поэтому их. следует применять с осторожностью. Ограничить Поскольку в обоих случаях за использованием конвертера следует применение стандартного преобразования, то обе последовательности одинаково хороши и компилятор не может выбрать ни одну из них.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |