Использование dllimport и dllexport в классах C++
Блок, относящийся только к системам Майкрософт
Классы C++ можно объявить с помощью или dllexport
атрибутаdllimport
. Эти формы подразумевают, что импортирован или экспортирован весь класс. Классы, которые можно экспортировать таким образом, называются экспортируемыми классами.
В следующем примере определяется экспортируемый класс. Экспортируются все его функции-члены и статические данные.
#define DllExport __declspec( dllexport )
class DllExport C {
int i;
virtual int func( void ) { return 1; }
};
Обратите внимание, что явное использование dllimport
атрибутов и dllexport
атрибутов для членов экспортируемого класса запрещено.
Классы dllexport
При объявлении класса dllexport
экспортируются все его функции-члены и статические элементы данных. Необходимо предоставить определения всех таких членов в одной программе. В противном случае возникает ошибка компоновщика. Единственным исключением из этого правила являются чистые виртуальные функции, для которых не требуется предоставлять явные определения. Однако, поскольку деструктор абстрактного класса всегда вызывается деструктором базового класса, чистые виртуальные деструкторы должны всегда предоставлять определение. Обратите внимание, что те же правила применяются и к неэкспортируемым классам.
При экспорте данных типа класса или функций, которые возвращают классы, не забудьте экспортировать класс.
Классы dllimport
При объявлении класса dllimport
импортируются все его функции-члены и статические элементы данных. В отличие от поведения и dllexport
неклассовых типов статические dllimport
элементы данных не могут указывать определение в той же программе, в которой dllimport
определен класс.
Наследование и экспортируемые классы
Все базовые классы экспортируемого класса должны быть экспортируемыми. В противном случае создается предупреждение компилятора. Кроме того, все доступные члены, которые также являются классами, должны быть доступными для экспорта. Это правило позволяет классу dllexport
наследоваться от класса, а dllimport
класс наследуется от dllimport
dllexport
класса (хотя последний не рекомендуется). Как правило, все, что доступно клиенту библиотеки DLL (в соответствии с правилами доступа C++), должно быть частью экспортируемого интерфейса. Сюда входят закрытые данные-члены, на которые ссылаются встраиваемые функции.
Выборочный элемент импорт и экспорт
Поскольку функции-члены и статические данные в классе неявно имеют внешнюю компоновку, их можно объявить с dllimport
помощью или dllexport
атрибута, если только весь класс не экспортируется. Если весь класс импортируется или экспортируется, явное объявление функций-членов и данных dllimport
dllexport
запрещено. Если вы объявляете статический элемент данных в определении класса как dllexport
, определение должно происходить где-то в той же программе (как и с внешней компоновкой некласса).
Аналогичным образом можно объявить функции-члены с dllimport
помощью или dllexport
атрибутов. В этом случае необходимо указать dllexport
определение в той же программе.
Обратите внимание на несколько важных аспектов выборочного импорта и экспорта членов.
Выборочный импорт и экспорт членов рекомендуется использовать для предоставления версии экспортированного интерфейса класса, который является более ограничивающим, то есть для которого можно разработать библиотеку DLL, предоставляющую меньше открытых и закрытых компонентов, чем разрешил бы язык. Кроме того, это может пригодиться для точной настройки экспортируемого интерфейса: если известно, что клиент по определению не может получить доступ к некоторым закрытым данным, не требуется экспортировать целый класс.
При экспорте одной виртуальной функции в классе необходимо экспортировать все функции или хотя бы предоставить версии, которые клиент может использовать напрямую.
Если имеется класс, в котором используется выборочный импорт и экспорт членов с виртуальными функциями, функции должны быть расположены в экспортируемом интерфейсе или определены встроенным образом (видимым клиенту).
Если вы определяете член как
dllexport
, но не включаете его в определение класса, создается ошибка компилятора. Необходимо определить член в заголовке класса.Несмотря на то, что определение членов класса разрешено
dllimport
илиdllexport
разрешено, нельзя переопределить интерфейс, указанный в определении класса.Если вы определяете функцию-член в месте, отличном от текста определения класса, в котором он объявлен, создается предупреждение, если функция определена как
dllexport
илиdllimport
(если это определение отличается от указанного в объявлении класса).
Завершение блока, относящегося только к системам Майкрософт
См. также
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по