Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Избавиться от заголовков библиотеки  (Прочитано 6943 раз)
0 Пользователей и 1 Гость смотрят эту тему.
RXL
Технический
Администратор

ru
Online Online
Пол: Мужской

WWW
« : 05-03-2008 21:58 » 

Задачка такая вот.
Есть несколько очень массивных модулей в проекте. 4 модуля на паскале (delphi) весят 5МБ. 4 C++ заголовка к ним весят 3МБ. Это результат импортирования библиотек типов COM. Хочу избавиться от них - вынести из проекта. Собственно, мне не нужно только часть функционала, но резать библиотеку не хочу.

Я выделяю эти модули в отдельный проект. На выходе: dll, lib, и те же 4 огромных заголовка.

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

Сколько не делай оболочек, а заголовки, получается, нужно тянуть от всех.

Попробуем на примерах.

1. dll1.h

Код: (C++)
class C1
{
};

2. dll2.h

Код: (C++)
#include "dll1.h"

class C2
{
  private:
    C1 *var;
  public:
    void useVar(void);
}

3. main.cpp

Код: (C++)
#include "dll2.h"

C2 myVar;

Здесь косвенно по прежнему используются заголовки dll1.

Таки есть идеи, как от этого избавиться?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 05-03-2008 22:28 » 

Навскидку: можно сделать
dll2.h:
Код:
class C1;

class C2
{
  private:
    C1 *var;
  public:
    void useVar(void);
}

dll2.cpp:

Код:
#include "dll2.h"
#include "dll1.h"

// C2 class definition

Не знаю, как в dll, в обычном проекте так работает (и встречал рекомендации по отвязыванию своих заголовков от избыточных включений, как раз с таким решением)
Записан
RXL
Технический
Администратор

ru
Online Online
Пол: Мужской

WWW
« Ответ #2 : 05-03-2008 22:38 » 

Вад, спасибо, попробую.

Т.е. получается, что dll1.h я для приложения превращая в набор деклараций без описания.
« Последнее редактирование: 05-03-2008 22:43 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 05-03-2008 23:02 » 

Если я не ошибаюсь (а если ошибаюсь, пусть меня поправят), для объявления члена-указателя на тип всегда достаточно его предварительного объявления. Полное объявление потребуется только в момент использования. В рамках одного проекта это хорошо работает, с dll редко дело имел, поэтому не знаю, не аукнется ли при линковке этот финт...

Немного не то тут написал, так что если кто прочитал - забудьте Улыбаюсь)

Я так понимаю, в dll2.cpp включаются все нужные объявления целиком, а в dll2.h включаются только предварительные объявления. Тогда dll1.h должна содержать полные объявления. Конечный пользователь (main.cpp) видит только предварительные.
« Последнее редактирование: 05-03-2008 23:19 от Вад » Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #4 : 06-03-2008 05:22 » 

RXL, используй идому pImpl
то что Вад написал.

я pImpl обычно делаю так.
wrapper.h
Код:
class WrapperImpl;

class Wrapper
{
boost:scoped_ptr<WrapperImpl> pImpl;
public:
void method();
~Wrapper(); // явное объявление деструктора требует boost:scoped_ptr
}

wrapper.cpp
Код:
#include "wrapper.h"
#include "external_dll.h"

class WrapperImpl // этот класс выполняет всю работу с внешней dll
{
void method()
{
external_dll_method();
}
}

void Wrapper::Wrapper():pImpl(new WrapperImpl()){}

void Wrapper::~Wrapper(){}

void C1::method()
{
pImpl->method();
}

второй варинт
wrapper.h
Код:
class IWrapper
{
public:
virtual void method() = 0;
virtual ~IWrapper();
}

IWrapper * GetWrapper();

dll.cpp
Код:
include "wrapper.h"
include "external_dll.h"

class WrapperImpl::public IWrapper // этот класс выполняет всю работу с внешней dll
{
virtual void method()
{
external_dll_method();
}

virtual ~WrapperImpl ();
}

IWrapper * GetWrapper (){ return new WrapperImpl (); }
« Последнее редактирование: 11-03-2008 05:10 от LogRus » Записан

Странно всё это....
RXL
Технический
Администратор

ru
Online Online
Пол: Мужской

WWW
« Ответ #5 : 06-03-2008 11:44 » 

LogRus, извиняй, но я ничего не понял. Расскажи подробнее.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 06-03-2008 13:17 » 

RXL, во втором варианте по виду это функция, порождающая объекты нужного класса (и его подклассов) и возвращающая указатели на эти объекты. Шаблон проектирования "фабричный метод", только это не метод Улыбаюсь.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

ru
Online Online
Пол: Мужской

WWW
« Ответ #7 : 06-03-2008 20:53 » 

Я использовал пустые объявления классов. Проект скомпилился удачно. Странно, что я вообще о таком способе не подумал.

Фабрики мне не нужны. Я просто спрятал все тонкости работы внутри ddl2. Общение с приложением - типами рантайм-библиотеки и их коллекциями. Обожаю строки: map<AnsiString, Variant> - набор параметров можно варьировать очень гибко.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #8 : 07-03-2008 05:35 » 

RXL, а чего тут объяснять
1. вариант просто использует идиому pImpl(можно почитать у Саттера или Александреску ну в гугле), т.е. предварительно обявляем класс реализацию, далее создаём класс интерфейс к реализации в класс интерфейс помещаем указатель на реализацию, работает т.к. для указателя или ссылки на класс не обязательно знать его размер, достаточно знания о размере указателя
Делее в cpp файле уже описываем класс реализацию инициализируем указатель прямо в конструкторе(я использовал вмето обычного указателя умный, защищает проблем с исключениями в конструкторе + не надо думать о вызове delete при разрушении объекта)
Из класса интерфейса завём методы класса реализации
Этой штукой пользуемся периодически для сокрытия зависимостей не нужных(твой случай)

2. вариант в котором используются полиморфиз
реализовал виртуальный интерфейс в хедере
реализация интерфейса в cpp
также в хедер поместил функцию котора возвращяет указатель на интерфейс, функция просто внутри делает new для реализации
можно сказать, что это фабрика
это штукой не пользуемся, ибо полиморфизм в принцепе редко используем
« Последнее редактирование: 07-03-2008 05:37 от LogRus » Записан

Странно всё это....
RXL
Технический
Администратор

ru
Online Online
Пол: Мужской

WWW
« Ответ #9 : 07-03-2008 09:26 » 

LogRus, я думаю, что твои примеры не подходят под мои условия. Или я их не понял.

У меня условия такие: dll1 полностью не мой - это генерит импортер библиотеки типов. Причем текст модулей на паскале (при их компиляции генерятся сишные заголовки - руками менять их бесполезно). Оболочку dll2 я делаю сам по любому (и не важно, войдет ли она физически в состав dll1 или выделится в dll2), т.к. работа с COM-объектами неудобна и логику полезно обобщить, заключив ее в класс. Все объекты классов dll1 создаются и уничтожаются внутри классов dll2 и далее нигде не видны.

Еще раз: dll1 менять нельзя, dll2 можно менять как угодно. Нужно только избавиться от заголовков на следующем уровне.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 07-03-2008 12:55 » 

RXL, так вот и пытаются объяснить, что: в заголовки DLL2 заголовки DLL1 не включаются (используются лишь указатели на классы DLL1, для которых описание самих классов не нужно); заголовки DLL1 включаются только в реализацию DLL2.

В результате пользователь получит собранные DLL1, DLL2 и заголовки DLL2.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

ru
Online Online
Пол: Мужской

WWW
« Ответ #11 : 07-03-2008 23:50 » 

dimka, я так и сделал - проблема решена. Просто не хочу бросать советы, которые я не понял. Хочу понять.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 08-03-2008 12:17 » 

RXL, так раз сделал, то вот оно и есть - так вот и работает... Что ещё остаётся непонятным?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #13 : 11-03-2008 05:02 » 

LogRus, я думаю, что твои примеры не подходят под мои условия. Или я их не понял.

Думаю второе Улыбаюсь
Возможно путанится возникла из-за того что у меня имена хедеров другие.
Суть в моих примерах одна и таже: сокрытие зависимостей и реализации

ладно давай в других терминах Улыбаюсь поправил сообщение с кодом изменив имена классов на мнемонические

в первом случае, ты в реализации явно зовёшь методы из класса реализации
не нужна фабрика, объект Wrapper можно создать на стеке
это, то, что предлагал Вад, только вместо указателя используется умный указатель

во втором эта работа делается механизмами полиморфизма
нужна фабрика(функция возвращающая реализацию)

вот пара статей
http://www.ddj.com/cpp/184401705
http://www.ddj.com/cpp/205918714

была еще статейка, как жестоким хаком сделать pImpl без хранения указателя
суть примерно такая
Код:
class Wrapper
{
    void method() {  reinterpret_cast<Impl*>(this)->method(); }
}

Wrapper* GetWraper(){ return reinterpret_cast<Wrapper*>(new Impl());}

« Последнее редактирование: 11-03-2008 05:29 от LogRus » Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines