Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 13.12.2020

Просмотров: 4135

Скачиваний: 28

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Глава 11. Дополнение к функциям языка C 

151 

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

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

  (implicit 

conversion  sequence)  аргумента.  Из  самого  названия  этой  после-
довательности  видно,  что  она  описывает  последовательные  пре-
образования типов, которые позволяют привести тип аргумента в 
вызове  функции  к  типу  соответствующего  параметра  в  объявле-
нии функции. Последовательности неявных преобразований ран-
жируются,  что  позволяет  компилятору  выбрать  наилучшую  из 
осуществимых функций. Компилятор выбирает эту функцию та-
ким образом, что для каждого параметра этой функции последо-
вательность  неявных  преобразований  имеет  ранг  не  ниже  по 
сравнению  с  соответствующими  рангами  последовательностей 
неявных  преобразований  других  осуществимых  функций.  Если 
наилучшая из осуществимых функций не единственна, то компи-
лятор выдает сообщение об ошибке. 
Приведем  ранжирование последовательностей  неявных  преобра-
зований аргументов. 
Сначала последовательности неявных преобразований делятся на 
следующие три группы: 

 

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

 

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

 

последовательности  преобразования  в  неопределенные  пара-
метры. 

Ранги  этих  групп  понижаются  от  первой  к  последней  группе. 
Причем  в  каждой  группе  последовательности  неявных  преобра-
зований также ранжируются. 
Группа последовательностей стандартных преобразований разби-
вается на следующие подгруппы: 

 

точное совпадение: 

 

не требуется преобразования типов; 

 

преобразование L-value в R-value; 


background image

Часть II. Язык программирования С++ 

152 

 

преобразование массива в указатель; 

 

преобразование квалификаторов 

const

 и 

volatile

 

продвижение по типам: 

 

интегральное продвижение; 

 

плавающее продвижение; 

 

стандартные преобразования типов: 

 

целочисленные преобразования без продвижения; 

 

преобразования  типов  с  плавающей  точкой  без  продви- 
жения; 

 

преобразования из целочисленного типа в плавающий тип; 

 

преобразования указателей; 

 

преобразования в тип данных 

bool

 

преобразования указателей на члены классов. 

Ранги  этих  подгрупп  понижаются  от  первой  к  последней  под-

группе.  То  есть  подгруппа  точное  совпадение  имеет  наивысший 

ранг.  Компилятор  ранжирует  последовательность  стандартных 

преобразований  по  наихудшему  преобразованию  типов  в  этой 

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

neg

, определенных выше. 

  float f = neg(5.5f);  // вызывается функция neg(float) 
  char c = abs(‘a’);    // вызывается neg(int) 
  double d = neg(5.5);  // ошибка 

В первом случае преобразование типов не требуется, т. к. тип ар-
гумента точно совпадает с типом параметра функции 

neg(float)

Во втором случае точного соответствия типов нет, но наилучшим 

преобразованием  типа  аргумента  является  интегральное  продви-
жение,  поэтому  вызывается  функция 

neg(int)

.  В третьем случае 

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

double

, а второе к типу 

int

, и оба этих преобразования имеют одинаковый ранг. 

Группа  последовательностей  определенных  пользователем  пре-
образований содержит такие последовательности, которые вклю-


background image

Глава 11. Дополнение к функциям языка C 

153 

чают  преобразование  типов  данных,  определенное  пользовате-
лем. Эти последовательности имеют следующую структуру. Сна-
чала  следует  последовательность  стандартных  преобразований, 
за которой следует определенное пользователем преобразование. 
Завершающей  является  опять  последовательность  стандартных 
преобразований.  Очевидно,  что  первый  и  третий  этапы  такого 
преобразования могут отсутствовать. 
В качестве преобразования типов, определенного пользователем, 
может  выступать  конструктор  класса  или  конвертер,  т. е.  функ-
ция  класса,  которая  используется  для  преобразования  типа  
объекта. 
Компилятор сравнивает последовательности определенных поль-
зователем  преобразований  только  в  том  случае,  если  они  име- 
ют  одинаковые  преобразования,  определенные  пользователем.  
В  противном  случае  последовательности  не  сравнимы  и  компи-
лятор выдает сообщение об ошибке. При сравнении таких после-
довательностей  компилятор  считает,  что  одна  последователь-
ность определенных пользователем преобразований лучше другой, 
если  вторая  последовательность  стандартных  преобразований  в 
этой  последовательности  имеет  высший  ранг  по  сравнению  с 
рангом второй последовательности стандартных преобразований 
в другой последовательности. 
Группа  последовательностей  преобразований  в  неопределенные 
параметры  содержит  последовательности,  которые  включают 
преобразования  аргументов  для  функций  с  неопределенным  ко-
личеством  параметров.  Если  существует  несколько  таких  после-
довательностей, то компилятор считает наилучшей ту из них, ко-
торая содержит меньше неопределенных типов аргументов. 
Возможность функций с разными сигнатурами иметь одно и то же 
имя называется 

перегружающим

 (overloading) 

полиморфизмом

11.5. Искажение имен функций 

Для  реализации  перегрузки  функций  компилятор  добавляет  к 
внутреннему имени функции дополнительные символы, которые 
определяют тип и порядок параметров функции. Такое именова-


background image

Часть II. Язык программирования С++ 

154 

ние  функций  называется 

декорированием

  (decorating)  или 

иска-

жением

  (mangling) 

имен  функций

.  К  сожалению,  декорирование 

имен функций не стандартизировано и поэтому в каждом компи-
ляторе определяется свой порядок декорирования имен. 
Из определения декорирования следует, что из программы, напи-
санной на языке программирования С++, нельзя непосредственно 
вызвать функцию из объектного модуля, полученную при помо-
щи  компилятора  языка  программирования  С.  Чтобы  решить  эту 
проблему, в языке программирования С++ введена 

спецификация 

связывания

, которая имеет следующий синтаксис: 

  extern "C" имя_функции 

или: 

  extern "C" 
  { 
    // блок объявления имен 
  } 

Заметим, что блок объявления имен может содержать как имена 
функций, так и имена переменных. 
Например,  предположим,  что  в  программе  на  языке  программи-
рования С++ используется функция 

fun

 из объектной библиотеки, 

разработанной  на  языке  программирования  C,  и  эта  функция 
имеет следующий прототип: 

  int fun(int); 

Тогда в этой программе для разрешения связей между объектны-
ми модулями нужно использовать спецификацию сцепления: 

  extern "C" int fun(int); 

Теперь предположим, что в программе на языке программирова-
ния C++ используются функции из библиотеки, разработанной на 
языке программирования С, а прототипы этих функций описаны 
в заголовочном файле import.h. Тогда в этой программе для раз-
решения  связей  между  объектными  модулями  нужно  использо-
вать спецификацию сцепления 

  extern "C" { #include import.h } 


background image

  

 
 

Г Л А В А  

12 

 
 
 

Пространства имен 

 

12.1. Определение  
пространства имен 

Пространство имен

  определяет  область  видимости  имен  объек-

тов,  которые  не  входят  ни  в  один  блок.  Поэтому  пространство 
имен не может быть определено внутри блока. Объявление про-
странства имен имеет следующий синтаксис: 

  namespace идентификатор 
  { 
    // тело пространства имен 
  } 

Здесь 

идентификатор

  определяет  имя  пространства  имен,  а  тело 

пространства  имен  содержит  описания  и  определения  имен.  На-
пример, определим пространство имен 

MyNames

, которое содержит 

определение одной переменной и одной функции. 

  namespace MyNames 
  { 
    int m; 
    int add(int a, int b) { return a + b; } 
  } 

Пространства  имен 

открыты

,  т. е.  одно  и  то  же  пространство 

имен  можно  расширять  в  разных  исходных  файлах.  Например, 

  

 


Смотрите также файлы