|
Программирование >> Инициализация объектов класса, структура
unsigned int a; print( a ); соответствует print( char ); print( a ); соответствует print( const char* ); то каждый из следующих трех вызовов дает точное соответствие: print( a ); соответствует print( unsigned int ); соответствие с преобразованием типа. Тип фактического аргумента не void ff( char ); соответствует типу формального параметра, но может быть преобразован в него: ff( 0 ); аргумент типа int приводится к типу char отсутствие соответствия. Тип фактического аргумента не может быть приведен к типу формального параметра в объявлении функции, поскольку необходимого преобразования не существует. Для каждого из следующих двух функции print() объявлены так же, как и выше *ip; class SmallInt { /* ... */ }; SmallInt si; print( ip ); ошибка: нет соответствия вызовов функции print () соответствия нет: print( si ); ошибка: нет соответствия Для установления точного соответствия тип фактического аргумента необязательно должен совпадать с типом формального параметра. К аргументу могут быть применены некоторые тривиальные преобразования, а именно: преобразование l-значения в г-значение; преобразование массива в указатель; преобразование функции в указатель; преобразования спецификаторов. (Подробнее они рассмотрены ниже.) Категория соответствия с преобразованием типа является наиболее сложной. Необходимо рассмотреть несколько видов такого приведения: расширение типов (promotions), стандартные преобразования и определенные пользователем преобразования. (Расширения типов и стандартные преобразования изучаются в этой главе. Онределенн1е пользователем преобразования будут нредставлены позднее, после детального рассмотрения классов; они выполняются конвертером, функцией-членом, которая позволяет определить в классе собственн1й набор стандартных трансформаций. В главе 15 мы познакомимся с такими конвертерами и с тем, как они влияют на разрешение перегрузки функций.) int max( int, int ); double max( double, double ); int i1; void calc( double d1 ) { max( 56, i1 ); точно соответствует max( int, int ); max( d1, 66.9 ); точно соответствует max( double, double ); объявлений: Перечислимый тип точно соответствует только определенным в нем элементам = 128; VIRTUAL = 129; }; Tokens enum Tokens { INLINE = : Tokens curTok = INLINE; enum Stat { Fail, Pass }; extern void ff( Tokens ); extern void ff( Stat ); extern void ff( int ); int main() { ff( Pass ); точно соответствует ff( Stat ) ff( 0 ); точно соответствует ff( int ) ff( curTok ); точно соответствует ff( Tokens ) ... перечисления, а также объектам, которые объявлены как принадлежащие к этому типу: Выше уже упоминалось, что фактический аргумент может точно соответствовать формальному параметру, даже если для приведения их типов необходимо некоторое тривиальное преобразование, первое из которых - преобразование 1-значения в г-значение. Под 1-значением понимается объект, удовлетворяющий следующим условиям: можно получить адрес объекта; можно получить значение объекта; При выборе лучшей из устоявших функций для данного вызова компилятор ищет функцию, для которой применяемые к фактическим аргументам преобразования являются наилучшими . Преобразования типов ранжируются следующим образом: точное соответствие лучше расширения типа, расширение типа лучше стандартного преобразования, а оно, в свою очередь, лучше определенного пользователем преобразования. М1 еще вернемся к ранжированию в разделе 9.4, а пока на простых примерах покажем, как оно помогает выбрать наиболее подходящую функцию. 9.3.1. Подробнее о точном соответствии Самый простой случай возникает тогда, когда типы фактических аргументов совпадают с типами формальных параметров. Например, есть две показанные ниже перегруженные функции max() . Тогда каждый из вызовов max() точно соответствует одному из int calc( int ); int main() { int lval, res; lval = 5; lvalue: lval; rvalue: 5 res = calc( lval ); lvalue: res return 0; rvalue: временн объект для хранения значения, возвращаемого функцией calc() которое нельзя модифицировать. Вот простой пример: В нервом операторе присваивания неременная lval - это l-значение, а литерал 5 - г-значение. Во втором операторе присваивания res - это l-значение, а временный объект, в котором хранится результат, возвращаемый функцией calc() , - это г-значение. В некоторых ситуациях в контексте, где ожидается значение, можно использовать int obj1; int obj 2; int main() ... int local = objl + obj2; return 0; выражение, представляющее собой l-значение: Здесь objl и obj2 - это l-значения. Однако для выполнения сложения в функции miain() из неременн1х objl и obj2 извлекаются их значения. Действие, состоящее в извлечении значения объекта, представленного выражением вида l-значение, называется преобразованием l-значения в г-значение. Когда функция ожидает аргумент, переданный по значению, то в случае, если аргумент #include <string> string color( purple ); void print( string ); int main() { print( color ); точное соответствие: преобразование lvalue в rvalue return 0; является l-значением, выполняется его преобразование в г-значение: это значение легко модифицировать (если только в объявлении объекта нет спецификатора const). Напротив, г-значение - это выражение, значение которого вычисляется, или выражение, обозначающее временный объект, для которого нельзя получить адрес и значение
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |