|
Программирование >> Инициализация объектов класса, структура
int i; void calc( float ); int main() { calc ( i ); стандартное преобразование между це типом и типом с плавающей точкой потенциально опасно в зависимости от значения i return 0; преобразований, а не расширений типов. При вызове функции calc() применяется стандартное преобразование из целого типа int в тип с плавающей точкой float. В зависимости от значения переменной i может оказаться, что его нельзя сохранить в типе float без потери точности. Предполагается, что все стандартные изменения требуют одного объема работы. Например, преобразование из char в unsigned char не более приоритетно, чем из char в double. Близость типов не принимается во внимание. Если две устоявших функции требуют для установления соответствия стандартной трансформации фактического аргумента, то вызов считается неоднозначным и помечается компилятором как ошибка. extern void manip( long ); Например, если даны две перегруженные функции: extern void manip( float ); int main() { manip( 3.14 ); ошибка: неоднозначность manip( float ) не лучше, чем manip( int ) return 0; то следующий вызов неоднозначен: Константа 3.14 имеет тип double. С помощью того или иного стандартного преобразования соответствие может быть установлено с любой из перегруженных функций. Поскольку есть две трансформации, приводящие к цели, вызов считается неоднозначным. Ни одно преобразование не имеет преимущества над другим. Программист может разрешить неоднозначность либо путем явного приведения типа: manip ( static cast<long>( 3.14 ) ); manip( long ) либо используя суффикс, обозначающий, что константа принадлежит к типу float: Преобразования, относящиеся к группам 1, 2 и 3, потенциально опасны, так как целевой тип может и не обеспечивать представления всех значений исходного. Например, с помощью float нельзя адекватно представить все значения типа int. Именно по этой причине трансформации, входящие в эти группы, отнесены к категории стандартных void set(int*); int main() { преобразование указателя из 0 в int* применяется к аргументам в обоих вызовах set( 0L ); set( 0x00 ); return 0; целого типа: Константное выражение 0L (значение 0 типа long int) и константное выражение 0x00 (шестнадцатеричное целое значение 0) имеют целый тип и потому могут быть преобразованы в нулевой указатель типа int*. Но поскольку перечисления не относятся к целым типам, элемент, равный 0, не приводим enum EN { zr = 0 }; к типу указателя: set( zr ); ошибка: zr нельзя преобразовать в тип int* Вызов функции set() является ошибкой, так как не существует преобразования между значением zr элемента перечисления и формальным параметром типа int*, хотя zr равно 0. Следует отметить, что константное выражение 0 имеет тип int. Для его приведения к типу указателя требуется стандартное преобразование. Если в множестве перегруженных функций есть функция с формальным параметром типа int, то именно в ее пользу будет разрешена перегрузка в случае, когда фактический аргумент равен 0: manip ( 3.14F ) ); manip( float ) Вот еще несколько примеров неоднозначных вызовов, которые помечаются как ошибки, extern void farith( unsigned int ); extern void farith( float ); int main() { кажд из последующих вызовов неоднозначен farith( a ); аргумент имеет тип char farith( 0 ); аргумент имеет тип int farith( 2uL ); аргумент имеет тип unsigned long farith( 3.14159 ); аргумент имеет тип double farith( true ); аргумент имеет тип bool поскольку соответствуют нескольким перегруженным функциям: Стандартные преобразования указателей иногда противоречат интуиции. В частности, значение 0 приводится к указателю на любой тип; полученный таким образом указатель называется нулевым. Значение 0 может быть представлено как константное выражение void print( int ); void print( void * void * ); void set( const char * ); void set( char * ); int main () { print( 0 ); вызается print( int ) ; set( 0 ); неоднозначность return 0; При вызове print(int) имеет место точное соответствие, тогда как для вызова print(void*) необходимо приведение значения 0 к типу указателя. Поскольку соответствие лучше преобразования, для разрешения этого вызова выбирается функция print(int). Обращение к set() неоднозначно, так как 0 соответствует формальным параметрам обеих перегруженных функций за счет применения стандартной трансформации. Раз обе функции одинаково хороши, фиксируется неоднозначность. Последнее из возможных преобразований указателя позволяет привести указатель любого типа к типу void*, поскольку void* - это родовой указатель на любой тип данных. Вот #include <string> extern void reset( void * ); void func( int *pi, string *ps ) { ... reset( pi ); преобразование указателя: int* в void* / ... reset( ps ); преобразование указателя: string* в void* несколько примеров: Только указатели на типы данных могут быть приведены к типу void* с помощью typedef int (*PFV)(); extern PFV testCases[10]; PFV testCases[10]; массив указателей на функции extern void reset( void * ); int main() { ... reset( textCases[0] ); ошибка: нет стандартного преобразования между int(*)() и void* return 0; стандартного преобразования, с указателями на функции так поступать нельзя:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |