Экспортируется ли конструктор класса из разделяемой библиотеки?

У меня есть разделяемая библиотека lib.so, содержащая класс Foo. Я динамически загружаю (с dlopen в UNIX) lib.so. После загрузки я хочу создать экземпляр Foo.
Могу ли я просто использовать оператор new для создания объекта Foo, или мне придется создать экспортированный фабричный метод, помещенный в lib.so, который создаст этот объект для меня?

На самом деле, вопрос в том, экспортируется ли конструктор Foo и можно ли его просто вызвать с помощью оператора new. Я думаю, что все классы и методы в общей библиотеке в UNIX по умолчанию экспортируются, и мне не нужно экспортировать их явно, как в Windows dll.

Помимо сокрытия способа создания (и, возможно, инициализации) объекта Foo, есть ли другие причины для использования фабричного метода при создании объекта класса, содержащегося в разделяемой библиотеке?


person dragan.stepanovic    schedule 23.09.2010    source источник


Ответы (2)


Основной ответ - да. Однако дьявол кроется в деталях. В Windows при использовании компилятора Microsoft C++ ВСЕ символы, будь то методы, переменные и т. д., по умолчанию не экспортируются для DLL. Вам необходимо явно экспортировать функции, классы и/или глобальные переменные. Я полагаю, что это также относится и к компилятору Borlands (могу ошибаться).

Раньше с GCC все экспортировалось по умолчанию, и вы не могли это контролировать. Пару лет назад это изменилось с добавлением атрибута (я не могу точно вспомнить, как он назывался, но он работал аналогично эквивалентному Microsoft __declspec(dllexport) ).

Поэтому, если вы определите класс и пометите его как экспортированный (как бы вы это ни выбрали), его конструктор будет экспортирован. Однако, как упоминается в предыдущем постере, из-за природы C++ имя символа меняется в зависимости от того, какой компилятор вы используете, а также, иногда, от версии компилятора C++. Это не обязательно проблема, это зависит от того, как вы хотите использовать вещи, но это означает, что вы должны знать об этом.

person Jim Crafton    schedule 23.09.2010

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

Поэтому используйте фабричный подход и непрозрачные типы указателей C:

// .cpp file
class Foo { ... };

// .h file
struct FooHandle;

#ifdef __cplusplus
extern "C"
{
    FooHandle* constructFoo(...);
    void releaseFoo(FooHandle*);
    int someFooMethod(FooHandle*, int param1, ...);
}
#endif

Всегда используйте функции C и непрозрачные типы указателей при экспорте разделяемых библиотек.

person Alexandre C.    schedule 23.09.2010
comment
Я считаю, что GCC поддерживает совместимый API C++ до версии 3.3.6. См. stackoverflow.com/questions/3718746/g-version-compatibility. - person Zan Lynx; 23.09.2010
comment
@Zan: это не меняет проблемы: пользователь с другим компилятором не сможет импортировать общие объекты, скомпилированные с помощью gcc. - person Alexandre C.; 23.09.2010
comment
Вы сказали разные версии одного и того же компилятора, поэтому я и сделал комментарий. - person Zan Lynx; 23.09.2010