ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4278
Скачиваний: 28
Глава 11. Дополнение к функциям языка C
151
На третьем этапе из множества осуществимых функций выбира-
ется наилучшая из осуществимых функций, которая и вызывает-
ся. Для выбора наилучшей из осуществимых функций вводится
понятие
последовательности неявных преобразований
(implicit
conversion sequence) аргумента. Из самого названия этой после-
довательности видно, что она описывает последовательные пре-
образования типов, которые позволяют привести тип аргумента в
вызове функции к типу соответствующего параметра в объявле-
нии функции. Последовательности неявных преобразований ран-
жируются, что позволяет компилятору выбрать наилучшую из
осуществимых функций. Компилятор выбирает эту функцию та-
ким образом, что для каждого параметра этой функции последо-
вательность неявных преобразований имеет ранг не ниже по
сравнению с соответствующими рангами последовательностей
неявных преобразований других осуществимых функций. Если
наилучшая из осуществимых функций не единственна, то компи-
лятор выдает сообщение об ошибке.
Приведем ранжирование последовательностей неявных преобра-
зований аргументов.
Сначала последовательности неявных преобразований делятся на
следующие три группы:
последовательности стандартных преобразований;
последовательности определенных пользователем преобразо-
ваний;
последовательности преобразования в неопределенные пара-
метры.
Ранги этих групп понижаются от первой к последней группе.
Причем в каждой группе последовательности неявных преобра-
зований также ранжируются.
Группа последовательностей стандартных преобразований разби-
вается на следующие подгруппы:
точное совпадение:
не требуется преобразования типов;
преобразование L-value в R-value;
Часть 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
, и оба этих преобразования имеют одинаковый ранг.
Группа последовательностей определенных пользователем пре-
образований содержит такие последовательности, которые вклю-
Глава 11. Дополнение к функциям языка C
153
чают преобразование типов данных, определенное пользовате-
лем. Эти последовательности имеют следующую структуру. Сна-
чала следует последовательность стандартных преобразований,
за которой следует определенное пользователем преобразование.
Завершающей является опять последовательность стандартных
преобразований. Очевидно, что первый и третий этапы такого
преобразования могут отсутствовать.
В качестве преобразования типов, определенного пользователем,
может выступать конструктор класса или конвертер, т. е. функ-
ция класса, которая используется для преобразования типа
объекта.
Компилятор сравнивает последовательности определенных поль-
зователем преобразований только в том случае, если они име-
ют одинаковые преобразования, определенные пользователем.
В противном случае последовательности не сравнимы и компи-
лятор выдает сообщение об ошибке. При сравнении таких после-
довательностей компилятор считает, что одна последователь-
ность определенных пользователем преобразований лучше другой,
если вторая последовательность стандартных преобразований в
этой последовательности имеет высший ранг по сравнению с
рангом второй последовательности стандартных преобразований
в другой последовательности.
Группа последовательностей преобразований в неопределенные
параметры содержит последовательности, которые включают
преобразования аргументов для функций с неопределенным ко-
личеством параметров. Если существует несколько таких после-
довательностей, то компилятор считает наилучшей ту из них, ко-
торая содержит меньше неопределенных типов аргументов.
Возможность функций с разными сигнатурами иметь одно и то же
имя называется
перегружающим
(overloading)
полиморфизмом
.
11.5. Искажение имен функций
Для реализации перегрузки функций компилятор добавляет к
внутреннему имени функции дополнительные символы, которые
определяют тип и порядок параметров функции. Такое именова-
Часть 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 }
Г Л А В А
12
Пространства имен
12.1. Определение
пространства имен
Пространство имен
определяет область видимости имен объек-
тов, которые не входят ни в один блок. Поэтому пространство
имен не может быть определено внутри блока. Объявление про-
странства имен имеет следующий синтаксис:
namespace идентификатор
{
// тело пространства имен
}
Здесь
идентификатор
определяет имя пространства имен, а тело
пространства имен содержит описания и определения имен. На-
пример, определим пространство имен
MyNames
, которое содержит
определение одной переменной и одной функции.
namespace MyNames
{
int m;
int add(int a, int b) { return a + b; }
}
Пространства имен
открыты
, т. е. одно и то же пространство
имен можно расширять в разных исходных файлах. Например,