Использование 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 класс наследуется от dllimportdllexport класса (хотя последний не рекомендуется). Как правило, все, что доступно клиенту библиотеки DLL (в соответствии с правилами доступа C++), должно быть частью экспортируемого интерфейса. Сюда входят закрытые данные-члены, на которые ссылаются встраиваемые функции.

Выборочный элемент импорт и экспорт

Поскольку функции-члены и статические данные в классе неявно имеют внешнюю компоновку, их можно объявить с dllimport помощью или dllexport атрибута, если только весь класс не экспортируется. Если весь класс импортируется или экспортируется, явное объявление функций-членов и данных dllimportdllexport запрещено. Если вы объявляете статический элемент данных в определении класса как dllexport, определение должно происходить где-то в той же программе (как и с внешней компоновкой некласса).

Аналогичным образом можно объявить функции-члены с dllimport помощью или dllexport атрибутов. В этом случае необходимо указать dllexport определение в той же программе.

Обратите внимание на несколько важных аспектов выборочного импорта и экспорта членов.

  • Выборочный импорт и экспорт членов рекомендуется использовать для предоставления версии экспортированного интерфейса класса, который является более ограничивающим, то есть для которого можно разработать библиотеку DLL, предоставляющую меньше открытых и закрытых компонентов, чем разрешил бы язык. Кроме того, это может пригодиться для точной настройки экспортируемого интерфейса: если известно, что клиент по определению не может получить доступ к некоторым закрытым данным, не требуется экспортировать целый класс.

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

  • Если имеется класс, в котором используется выборочный импорт и экспорт членов с виртуальными функциями, функции должны быть расположены в экспортируемом интерфейсе или определены встроенным образом (видимым клиенту).

  • Если вы определяете член как dllexport , но не включаете его в определение класса, создается ошибка компилятора. Необходимо определить член в заголовке класса.

  • Несмотря на то, что определение членов класса разрешено dllimport или dllexport разрешено, нельзя переопределить интерфейс, указанный в определении класса.

  • Если вы определяете функцию-член в месте, отличном от текста определения класса, в котором он объявлен, создается предупреждение, если функция определена как dllexport или dllimport (если это определение отличается от указанного в объявлении класса).

Завершение блока, относящегося только к системам Майкрософт

См. также

dllexport, dllimport