KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Стенли Липпман - Язык программирования C++. Пятое издание

Стенли Липпман - Язык программирования C++. Пятое издание

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн "Стенли Липпман - Язык программирования C++. Пятое издание". Жанр: Программирование издательство -, год -.
Перейти на страницу:

#include <string.h> // функции языка С, манипулирующие строками

                    // в стиле С

}

Когда директива #include заключена в фигурные скобки составной директивы компоновки, все объявления обычных функций в файле заголовка будут восприняты как написанные на языке, указанном в директиве компоновки. Директивы компоновки допускают вложенность, т.е. если заголовок содержит функцию с директивой компоновки, на данную функцию это не повлияет.

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

Указатели на функции, объявленные в директиве extern "С"

Язык, на котором написана функция, является частью ее типа. Чтобы объявить указатель на функцию, написанную на другом языке программирования, следует использовать директиву компоновки. Кроме того, указатели на функции, написанные на других языках, следует объявлять с той же директивой компоновки, что и у самой функции:

// pf указывает на функцию С, возвращающую void и получающую int

extern "С" void (*pf) (int);

Когда указатель pf используется для вызова функции, созданный при компиляции код подразумевает, что происходит обращение к функции С.

Тип указателя на функцию С не совпадает с типом указателя на функцию С++. Указатель на функцию С не может быть инициализирован (или присвоен) значением указателя на функцию С++ (и наоборот). Как и при любом другом несовпадении типов, попытка присвоения указателя с другой директивой компоновки приведет к ошибке:

void (*pf1)(int);            // указатель на функцию С++

extern "С" void (*pf2)(int); // указатель на функцию С

pf1 = pf2; // ошибка: pf1 и pf2 имеют разные типы

Некоторые компиляторы С++ могут допускать присвоение, приведенное выше, хотя, строго говоря, оно некорректно.

Директивы компоновки применимы ко всем объявлениям

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

// f1() - функция С, ее параметр также является указателем на функцию С

extern "С" void f1(void(*)(int));

Это объявление свидетельствует о том, что f1() является функцией языка С, которая не возвращает никаких значений. Она имеет один параметр в виде указателя на функцию, которая ничего не возвращает и получает один параметр типа int. Эта директива компоновки применяется как к самой функции f1(), так и к указателю на нее. Когда происходит вызов функции f1(), ей необходимо передать имя функции С или указатель на нее.

Поскольку директива компоновки применяется ко всем функциям в объявлении, для передачи функции С++ указателя на функцию С необходимо использовать определение типа (см. раздел 2.5.1):

// FC - указатель на функцию С

extern "С" typedef void FC(int);

// f2 - функция С++, параметром которой является указатель на функцию С

void f2(FC *);

Экспорт функций, созданных на языке С++, в другой язык

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

// функция calc() может быть вызвана из программы на языке С

extern "С" double calc(double dparm) { /* ... */ }

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

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

Поддержка препроцессора при компоновке на языке С

Чтобы позволить компилировать тот же файл исходного кода на языке С или С++, при компиляции на языке С++ препроцессор автоматически определяет имя __cplusplus (два символа подчеркивания). Используя эту переменную, при компиляции на С++ можно условно включить код, компилируемый только на С++:

#ifdef __cplusplus

// ok: компилируется только в С++

extern "С"

#endif

int strcmp(const char*, const char*);

Перегруженные функции и директивы компоновки

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

Язык С не поддерживает перегрузку функций, поэтому нет ничего удивительного в том, что директива компоновки языка С может быть определена только для одной из функций в наборе перегруженных функций:

// ошибка: в директиве extern "С" указаны две одноименные функции

extern "С" void print(const char*);

extern "С" void print(int);

Если одна из функций в наборе перегруженных функций является функцией языка С, все остальные функции должны быть функциями С++:

class SmallInt { /* ... */ };

class BigNum { /* ... */ };

// функция С может быть вызвана из программ С и С++

// версия функции С++, перегружающая предыдущую функцию, может быть

// вызвана только из программ на языке С++

extern "С" double calc(double);

extern SmallInt calc(const SmallInt&);

extern BigNum calc(const BigNum&);

Версия функции calc() для языка С может быть вызвана как из программ на языке С, так и из программ на языке С++. Дополнительные функции с параметрами типа класса могут быть вызваны только из программ на языке С++, причем порядок объявления не имеет значения.

Упражнения раздела 19.8.3

Упражнение 19.26. Объясните эти объявления и укажите, допустимы ли они:

extern "С" int compute(int *, int);

extern "С" double compute(double *, double);

Резюме

Язык С++ предоставляет несколько специализированных средств, предназначенных для решения ряда специфических проблем.

Некоторым приложениям требуется взять под свой контроль распределение памяти. Это можно сделать, определив собственные версии (в классе или глобально) библиотечных функций operator new() и operator delete(). Если приложение определяет собственные версии этих функций, выражения new и delete будут использовать соответствующую версию, определенную приложением.

Некоторым программам необходимо непосредственно выяснять динамический тип объекта во время выполнения. Идентификация типов времени выполнения (Run-Time Type Identification — RTTI) предоставляет поддержку этого вида программирования на уровне языка. RTTI применима только к тем классам, которые обладают виртуальными функциями; информация о типах без виртуальных функций также доступна, но она соответствует статическому типу.

При определении указателя на член класса в состав его типа должен также входить тот класс, на член которого указывает указатель. Указатель на член класса может быть связан с членом любого объекта того же класса. При обращении к значению указателя на член класса необходимо указать объект, о члене которого идет речь.

В языке С++ определено несколько дополнительных составных типов.

• Вложенные классы, которые определены в области видимости другого класса. Такие классы зачастую применяют для реализации содержащего класса.

• Объединения — это специальный вид класса, объект которого может содержать только простые переменные-члены. В любой момент времени объект такого типа может содержать значение только в одной из его переменных-членов. Как правило, объединения входят в состав другого класса.

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

Язык С++ предоставляет также несколько средств, ухудшающих переносимость программ. Сюда относятся битовые поля, спецификатор volatile, упрощающий взаимодействие с аппаратными средствами, и директивы компоновки, упрощающие взаимодействие с программами, написанными на других языках.

Термины

Анонимное объединение (anonymous union). Безымянное объединение, которое не применимо для создания объекта. Члены анонимного объединения являются членами окружающей области видимости. Такие объединения не могут иметь ни функций-членов, ни закрытых или защищенных членов.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*