Как разделить классы между DLL - PullRequest
0 голосов
/ 30 апреля 2010

У меня есть неуправляемое приложение Win32 C ++, которое использует несколько библиотек C ++. Каждая из библиотек DLL должна использовать класс Foo - определение и реализация.

Где живут Foo.h и Foo.cpp, чтобы библиотеки DLL связывались и не дублировали код в памяти?

Разумно ли это делать?

[Изменить] В всех ответах и ​​комментариях много полезной информации, а не только той, которую я отметил в качестве ответа. Спасибо всем за участие.

Ответы [ 3 ]

5 голосов
/ 30 апреля 2010

Обеспечение функциональности в форме классов через DLL само по себе хорошо. Однако вы должны быть осторожны, чтобы отделить интерфейс от реализации. Насколько осторожно зависит от того, как будет использоваться ваша DLL. Для игрушечных проектов или утилит, которые остаются внутренними, вам даже не нужно думать об этом. Для библиотек DLL, которые будут использоваться несколькими клиентами в рамках компилятора who-знает-какой, вы должны быть очень осторожны.

Рассмотрим:

class MyGizmo
{
public:
  std::string get_name() const;
private:
  std::string name_;
};

Если MyGizmo будет использоваться третьими лицами, этот класс не вызовет у вас головной боли. Очевидно, что закрытые переменные-члены являются проблемой, но тип возвращаемого значения для get_name() является такой же проблемой. Причина в том, что детали реализации std::string являются частью его определения. Стандарт диктует минимальный набор функций для std::string, но разработчики компиляторов могут свободно реализовать то, что они выбирают. Один может иметь функцию с именем realloc() для обработки внутреннего перераспределения, в то время как другой может иметь функцию с именем buy_node() или что-то в этом роде. То же самое верно для членов данных. Одна реализация может использовать 3 size_t и char*, а другая может использовать std::vector. Дело в том, что ваш компилятор может подумать, что std::string - это n байтов и имеет такие-то члены, тогда как другой компилятор (или даже другой уровень патча того же компилятора) может подумать, что он выглядит совершенно иначе.

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

DLL.H:

class MyGizmo
{
public:
  static MyGizmo* Create();
  virtual void get_name(char* buffer_alloc_by_caller, size_t size_of_buffer) const = 0;
  virtual ~MyGizmo();
private:
  MyGizmo();  // nobody can create this except myself

};

... и затем во внутренних компонентах вашей DLL вы определяете класс, который фактически реализует MyGizmo:

mygizmo.cpp:

class MyConcreteGizmo : public MyGizmo
{
public:
  void get_name(char* buf, size_t sz) const { /*...*/ }
  ~MyGizmo() { /*...*/ }
private:
  std::string name_;
};

MyGizmo* MyGizmo::Create()
{
  return new MyConcreteGizmo;
}

Это может показаться болью, и это так. Если ваша DLL будет использоваться только внутренне только одним компилятором, возможно, нет причин идти на неприятности. Но если ваша DLL будет использоваться моими несколькими компиляторами для внутренних целей или для внешних клиентов, это избавит вас от головной боли в будущем.

2 голосов
/ 30 апреля 2010

Где живёт Фу? в другой dll.

Разумно ли? не совсем.

Если вы объявите класс следующим образом:

класс __declspec (dllexport) Foo {...

тогда msvc будет экспортировать все функции-члены класса. Однако полученный dll является очень хрупким, так как любое небольшое изменение в определении класса без соответствующей перестройки каждой потребляющей dll означает, что потребляющий код выделит неправильное количество байтов для любого стека и выделения кучи, не выполняемые фабричными функциями. Аналогично, встроенные методы будут компилироваться в потребляющие dll и ссылаться на старый макет класса.

Если все библиотеки всегда восстанавливаются вместе, тогда продолжайте. Если нет - не надо: P

2 голосов
/ 30 апреля 2010

Используйте __ declspec dllexport для экспорта класса в таблицу экспорта DLL, затем включите файл заголовка в другие ваши проекты и создайте ссылку на файл библиотеки экспорта основной DLL. Таким образом, реализация является распространенным явлением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...