2016-04-19 4 views
3

Я признаю, что этот вопрос звучит довольно общий. Но ведь экспортировать классы из DLL - общая и сложная тема, и, честно говоря, я в настоящее время запутался на довольно общем уровне.Могу ли я организовывать классы в DLL?

Короткий вопрос: Как объектно-ориентированное программирование на языках C++ и DLL сочетается?

Длинный вопрос: После прочтения this и this, я был немного разочарован и смущен, потому что я удивляюсь, как объектно-ориентированное программирование может работать с DLL, если DLL границы не позволяет объекты для совместного использования (при условии, что две библиотек DLL использовали разные компиляторы или версии компилятора). Единственные вариантами для экспорта классов являются этими (как описаны here или here):

  • экспорта создавать и удалять методы (C стиль, опасность оборванных указателей, никаких объектов в качестве параметров, некрасиво)
  • экспорта чистых виртуального класс и фабричную функцию, которая создает экземпляр фактического класса реализации, полученного из чистого виртуального класса (требуется наследование, удаление объекта необходимо позаботиться)

Например, я хотел бы разместить обычную утилиту классы в одной DLL, которые затем я использую в нескольких классах в других DLL , которые сами используются в других DLL. Как я могу это сделать? Является ли это неправильным способом организации моих занятий?

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

EDIT: Если это имеет значение, я нахожусь в Windows 7 с помощью Visual Studio 2010. Миграция vom старой Visual Studio сделала меня чувствительным к этой проблеме.

+0

Использование DLL - это очень прагматичное решение проблемы, связанной с необходимостью долго ждать, когда ваша программа скомпилирована и связана с небольшими изменениями. Используя их как библиотеку, которую нужно легко использовать в любой версии компилятора, используя любые параметры компиляции, ну, нет. Бинарная совместимость - это не C++-функция, которая должна быть добавлена ​​вами, и вы уже знаете, что это значит. –

+0

@Hans Passant: Есть ли альтернатива DLL для организации исходного кода в многоразовом режиме? Возможно, реализация заголовка? Что-нибудь еще? – Fabian

ответ

2

TL; DR: от этого зависит.

Простой случай

Когда две библиотеки DLL (или его DLL и исполняемым) были построены с тем же компилятором и версии компилятора, и они используют один и тот же аромат выполнения (отладки или выпуска), и они ссылку на динамическую версию среды выполнения, вы можете делать все, что хотите. Например, удалите границы DLL.

Чем меньше Простой случай

Когда одна DLL ссылка на отладочный выполнения и другой канал против выполнения выпуска, все становится сложнее. Это связано с тем, что время отладки имеет разные шаблоны STL для целей отладки. Например, вы не можете манипулировать std :: vector, выделенным из DLL отладки в DLL выпуска, и наоборот. Пока вы ограничиваете эти шаблоны STL в нужную DLL, все должно работать. Очевидно, что у вас возникнут проблемы, если вы сами откроете разные ABI, например, объявив член в блоке #ifndef NDEBUG.

Возможно, вам придется вынудить что-то немного с помощью _CRT*, чтобы это работало, в зависимости от того, какие шаблоны использует отладочная DLL.

Вы также должны создавать и уничтожать объекты из одной и той же библиотеки.

Грозный (а.к.а. Real World) Case

Когда версия компилятора не совпадает, когда по крайней мере одна DLL связана со статическим выполнением.

Вы столкнетесь с тоннами проблем с ABI. Единственное, что нужно сделать, это полагаться (широко) на C ABI через extern "C". Это также, вероятно, то, что вы хотите сделать, если вы загружаете DLL во время выполнения.

Хорошая вещь, чтобы сделать в этом пункте:

  • Написать DLL в C++
  • Не подвергайте (dllexport) ничего с помощью C++ ABI.
  • Напишите тонкую оболочку C вокруг кода на C++.
  • Expose this C API с __declspec(dllexport)
  • Создайте только C++-оболочку с открытым заголовком вокруг открытого C API.

Клиенты будут использовать вашу оболочку только для заголовков, поэтому каждый вызов вашего DLL-кода будет производиться с использованием C ABI, который чрезвычайно стабилен и вряд ли сломается.

+0

Является ли простой случай реалистичным? Что делать, если у меня есть целый набор, который я хочу перенести из одной версии компилятора в другую? Что люди делают в этом случае? Кроме того, вы могли бы более подробно объяснить, как выглядит тонкая оболочка C и оболочка C++ только для заголовка, может быть, с небольшим примером? Это было бы очень мило. – Fabian

1

Прошло много времени с тех пор, как я написал one of the questions you linked, но позвольте мне попытаться помочь.

Короткий вопрос: Как объектно-ориентированное программирование на языках C++ и DLL сочетается?

Это полностью зависит от того, какие предметы выставляете. Если ваши объекты возвращают значения plain-C, вы должны быть в порядке. Если ваши объекты возвращают классы POD, содержащие значения plain-C, вы также должны быть в порядке. Головные боли, которые я безуспешно пытался решить в этой группе вопросов/ответов, были почти полностью связаны с STL.

Чтобы ответить на вопрос о естественном вопросе, STL играет очень плохо с DLL. Классы C++ имеют врожденные проблемы совместимости с несколькими компиляторами из-за различной упаковки, переупорядочения членов и т. Д. STL добавляет дополнительный уровень потенциальной несовместимости, потому что, когда он встроен в отладочную DLL, могут добавляться дополнительные члены.

Например, я хотел бы разместить общие классы утилиты в одной DLL, которые затем я использую в нескольких классах в других DLL, которые сами используются в других DLL. Как я могу это сделать?

После успешного прохождения типов STL, я в конечном итоге завернул свои классы C++ в слой, который перевел их на свои C-копии и обратно. По возможности я возвращал базовые типы данных. Где мне пришлось выделять память (string, vector и т. Д.). В итоге я создал функции создания/удаления c-стиля. Я считаю, что я по-прежнему обнаружил чистый виртуальный интерфейс для защиты как можно большего числа деталей реализации; Я просто не пытался передавать какие-либо объекты STL непосредственно через границу DLL.

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

Если я правильно понял вопрос, вы хотите сделать то и другое.

struct MyDLL 
{ 
    virtual void DoSomething() = 0; 
    virtual int AddSomething(int argument1, int argument2) = 0; 
} 

extern "C" __declspec(dllexport) MyDLL* GetMyDLL(); 

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

+0

Можно ли использовать указатели для моих пользовательских классов в структуре POD? Указатель - это тип POD, правильно? Моя идея состоит в том, чтобы структура 'MyDLL' имела указатель на внутренний класс и позволяла' MyDLL' иметь обычные функции, которые делегируются внутреннему классу. – Fabian

+0

Мой вопрос, направленный на то, как люди живут с этой серьезной проблемой. Я хочу иметь возможность перемещать объекты вокруг своих DLL и не быть в состоянии безопасно делать это больно. Люди игнорируют возможные проблемы или заставляют своих разработчиков использовать один и тот же компилятор или они просто не разделяют ничего, кроме POD и ints? Возможно, мне тоже нужно изменить свой способ программирования. – Fabian

+0

До тех пор, пока вы не передаете класс C++ по границе EXE/DLL, я думаю, что с вами все в порядке. Я полагаю, ваш «указатель на пользовательский класс» будет функционировать так же, как код «MyDLL' /' GetMyDLL »в моем ответе? Это должно быть достаточно безопасным. Однако если вы попытаетесь выставить указатели на объекты STL, не ожидайте, что это закончится хорошо. Компилятор EXE может иметь разный макет памяти для этих объектов STL, заставляя указатель указывать на разные вещи между вашей DLL и EXE. – computerfreaker

Смежные вопросы