Форум программистов, компьютерный форум CyberForum.ru

Классы-посредники - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 4.64
thick_int
Заблокирован
24.11.2011, 00:05     Классы-посредники #1
Читая Дейтла, дошел до теемы классы-посредники, назначение которых скрыть не только реализацию, но и интерфейс класса (в том смысле, как я понял, чтобы пользователь класса просто не видел физически заголовочный файл класса).
Так ли уж ценна эта идея, искусственно накручивания скрытия всего и вся?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.11.2011, 00:05     Классы-посредники
Посмотрите здесь:

классы C++
C++ Классы
классы в с++ C++
Классы C++
классы C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.11.2011, 00:08     Классы-посредники #2
thick_int, Впервые о таком термине слышу... Вы имеете ввиду идиотму pimpl? Когда в классе хранится указатель на другой класс и работа вся идет через этот указатель?
thick_int
Заблокирован
24.11.2011, 00:14  [ТС]     Классы-посредники #3
Ну сразу, чтобы было понятно, о чем идет речь - это раздел 10.10, страница 681 из книги, которую я указал.
Что такое pimpl я не знаю, но там точно также приватным членом класса посредника действительно является указатель на реальный класс. Вообщем то метода работы понятна, хоть и несколько более канительно, непонятно только зачем так делать.
И разумеется, как то интуитивно кажется, что производительность от этого чуть-чуть, да страдает.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.11.2011, 00:19     Классы-посредники #4
thick_int, Ммм. Зато не страдает память. Вместо того, чтобы хранить в себе все данные объекта - класс хранит только указатель на impl-класс. Ну и плюс к тому - отделение интерфейса от реализации, т.е. у класса есть конкретный интерфейс, который не изменяется, а в impl-классе реализация может меняться как угодно.
thick_int
Заблокирован
24.11.2011, 00:24  [ТС]     Классы-посредники #5
Нет ну, если бы только один укзатель, тогда да. Но ведь все равно это никоим образом не устраняет необходимость все равно где-то хранить полный класс.
Я хочу понять смысл этой затеи. Там насколько я понял, товарищ Дейтла пропагандирует этот метод исключительно по тем соображениям, чтобы тот, кто пользуется классом, помимо того, чтобы не увидеть файл реализации, также еще не увидел и заголовок. Вот и все преимммущества, с его точки зрения. Я вот и хочу узнать в чем тут смысл, чтобы так все засекречивать.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.11.2011, 00:27     Классы-посредники #6
http://www.insidecpp.ru/patterns/pimpl_idiom
http://habrahabr.ru/blogs/cpp/118010/
Сыроежка
Заблокирован
24.11.2011, 00:33     Классы-посредники #7
Цитата Сообщение от thick_int Посмотреть сообщение
Читая Дейтла, дошел до теемы классы-посредники, назначение которых скрыть не только реализацию, но и интерфейс класса (в том смысле, как я понял, чтобы пользователь класса просто не видел физически заголовочный файл класса).
Так ли уж ценна эта идея, искусственно накручивания скрытия всего и вся?
Во-первых, вы не правильно поняли. Скрывается не интерфейс, а реализация! Интерфейс потому и называется интерфейсом, что он предназначен для открытого доступа.

Я хотя книгу не читал, но скорей всего имеется в виду метод проектирования под названием PIMPL. То есть реализация ( IMPlementation) выполнена в ддругом классе, а в основном классе имеется лишь указатель на класс реализации.

К сожалению этот способ сокрытия реализации не очень эффективен. Во-первых, добавляется лишний указатель. Очевидно, что при копировании объектов требуется использовать оператор new и delete либо для класса-посредника, либо для самого указателя.
Кроме того бывает так, что классу посреднику порой нужно обращаться к открытым функциям основного класса. Тогда в классе посреднике приходится в свою очередь делать указатель на основной класс, чтобы получить доступ к этим функциям.
thick_int
Заблокирован
24.11.2011, 00:41  [ТС]     Классы-посредники #8
Ну вообщемм пробежал и так понял, что пока еще рано вникато в эти тонкости.

А вот еще не поможете ли с этим, тоже по результатм чтения главы 10 этой же книги

Допустим, что у меня есть вот такой класс
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class T
{
public:
    T() : b(0) {}
 
    int f() const
    {
        return b;
    }
    int f()
    {
        b++;
        return b;
    }
private:
    int b;
};
Предположим, что в функции main я обявил две переменные класса T, одну неконстантную, а другую константную:
C++
1
2
T varT;
T const constT;
Я знаю, что для константного объекта будет вызвана константная функция, а для неконстантного объекта будет вызвана неконстантная функция (перегрузка).
Я также знаю, что вызов неконстантной функции с константным объектомм карается компилятором.
Осталось разобраться с последним, а именно а как вызвать константную функцию (перегрузка) (если это вообще возможно) для неконстантного объекта.
Интересует простой синтаксис, что то вроде
C++
1
varT.f()(const)
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.11.2011, 00:49     Классы-посредники #9
thick_int, Еще на работе приходится сейчас разбираться с библиотекой libarabica. Я конечно считаю, что они там переборщили с косвенностью, но реализация скрыта крайне грамотно.

Есть в include папка DOM. Классы в данных хедерах реализуют модель DOM для xml.
Допустим есть класс Node.
В себе он хранит Proxy<Node_impl> и работает соответственно исключительно через этот impl.
Где Proxy<Node_impl> хранит в себе указатель на Node_impl и обеспечивает доступ к нему.
В свою очередь Node_impl является абстрактным классом. Не хранит в себе никаких данных, только создает интерфейс.

Так же в DOM есть папка Simple, где в хедерах реализуются конкретные классы, унаследованные от интерфейсов.

В итоге есть класс SimpleDOM::Node_impl который наследуется от DOM::Node_impl и реализует этот интерфейс как пожелает разработчик.

Добавлено через 1 минуту
thick_int, Преобразовать к const и вызвать. Но оно того не стоит.
Сыроежка
Заблокирован
24.11.2011, 00:50     Классы-посредники #10
thick_int,

Что-то в голову ничего не лезет!

Но покрайней мере можете использовать такой код

C++
1
 const_cast<const T &>( varT ).f():
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
24.11.2011, 09:34     Классы-посредники #11
Цитата Сообщение от ForEveR Посмотреть сообщение
...
В себе он хранит Proxy<Node_impl> и работает соответственно исключительно через этот impl.
Где Proxy<Node_impl> хранит в себе указатель на Node_impl и обеспечивает доступ к нему.
В свою очередь Node_impl является абстрактным классом. Не хранит в себе никаких данных, только создает интерфейс.
...
В итоге есть класс SimpleDOM::Node_impl который наследуется от DOM::Node_impl и реализует этот интерфейс как пожелает разработчик.
То есть, получается, что есть парочка абстрактных классов сверху класса с данными, в которых реализуется распределенный интерфейс работы с данными основного класса.
И вся эффективность заключается вот в таком вот распределении методов и уровней доступа?

Таким образом на плечи пользователя такого интерфейса ложится использование и доработка функционала абстрактных классов, а разработчик библиотеки допинывает собственные методы класса с данными, стараясь не изменить при этом интерфейс доступа к нему.
Я правильно ухватил?
Bers
Заблокирован
24.11.2011, 09:59     Классы-посредники #12
Цитата Сообщение от BRcr Посмотреть сообщение
Таким образом на плечи пользователя такого интерфейса ложится использование и доработка функционала абстрактных классов,
Пользователи только пользуются. Они ничего не дорабатывают.

Разработчик библиотеки предоставляет пользователям класс, кишки которого надёжно упрятаны и не видны снаружи.

Профит тут ещё в том, что бизнес-логика целевого проекта уже никак не зависит от бизнес-логики библиотеки.
Изменения в реализации библиотеки никак не затронет бизнес-логику пользователя.
Тут можно ещё чуток подшаманить, и можно будит вносить в библиотеку модификации так, что приложение пользователя даже не придётся перекомпилировать)

Другой профит: использование pImpl в рамках одного проекта затрудняет модификации самих интерфейсов. Что приводит к их цементированию.

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

Один из минусов pImpl - архитектура становится железобетонной, и плохо реагирует на внесение изменений.

Другой минус - вынуждает разработчиков использовать new и delete на верхних уровнях.
Что при неграмотном использовании может сделать систему в целом менее надежной.
А городить вокруг pImpla систему ловушек для исключений на таком высоком уровне - хороший признак ещё раз пересмотреть архитектуру.

Правда есть один фокус, как можно использовать идиому pImpl, но при этом не использовать new delete. Гм... в общем то фокус этот я "изобрел" сам, но до ума его так и не довел (времени тогда не хватило)

Смысл фокуса - получить тот же самый pImpl вообще не используя new с delete
Правда в том виде, в каком технология находится сейчас, использовать её слишком опасно.
На защите идеи меня разгромили) Доказав, что возможные риски перевешивают профит)

Ну.. когда нибудь я доведу её до ума, и подарю Индустрии безопасный и высокоэффективный rImpl. Который (при грамотном подходе) не только безопаснее, но ещё и быстрее.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.11.2011, 11:45     Классы-посредники #13
Bers,
Пользователи только пользуются. Они ничего не дорабатывают.
Пользователь пользователю рознь.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
////////////////////////////////////////////////////////////////////
// derive from this class to implement your own
// DOM provider
template<class stringT, class string_adaptorT> class Document_impl;
template<class stringT, class string_adaptorT> class NodeList_impl;
template<class stringT, class string_adaptorT> class NamedNodeMap_impl;
 
template<class stringT, class string_adaptorT>
class Node_impl
{
  public:
    virtual ~Node_impl() { }
 
    ///////////////////////////////////////////////////////
    // Ref counting
    virtual void addRef() = 0;
    virtual void releaseRef() = 0;
 
    ///////////////////////////////////////////////////////
    // Node methods
    virtual const stringT& getNodeName() const = 0;
 
    virtual const stringT& getNodeValue() const = 0;
    virtual void setNodeValue(const stringT& nodeValue) = 0;
 
    virtual Node_base::Type getNodeType() const = 0;
    
    virtual Node_impl<stringT, string_adaptorT>* getParentNode() const = 0;
 
    virtual NodeList_impl<stringT, string_adaptorT>* getChildNodes() const = 0;
    
    virtual Node_impl<stringT, string_adaptorT>* getFirstChild() const = 0;
    virtual Node_impl<stringT, string_adaptorT>* getLastChild() const = 0;
 
    virtual Node_impl<stringT, string_adaptorT>* getPreviousSibling() const = 0;
    virtual Node_impl<stringT, string_adaptorT>* getNextSibling() const = 0;
 
    virtual NamedNodeMap_impl<stringT, string_adaptorT>* getAttributes() const = 0;
 
    virtual Document_impl<stringT, string_adaptorT>* getOwnerDocument() const = 0;
 
    virtual Node_impl<stringT, string_adaptorT>* insertBefore(Node_impl<stringT, string_adaptorT>* newChild, Node_impl<stringT, string_adaptorT>* refChild) = 0;
    virtual Node_impl<stringT, string_adaptorT>* replaceChild(Node_impl<stringT, string_adaptorT>*  newChild, Node_impl<stringT, string_adaptorT>* oldChild) = 0;
    virtual Node_impl<stringT, string_adaptorT>* removeChild(Node_impl<stringT, string_adaptorT>*  oldChild) = 0;
    virtual Node_impl<stringT, string_adaptorT>* appendChild(Node_impl<stringT, string_adaptorT>*  newChild) = 0;
    virtual void purgeChild(Node_impl<stringT, string_adaptorT>* oldChild) = 0;
 
    virtual bool hasChildNodes() const = 0;
 
    virtual Node_impl<stringT, string_adaptorT>* cloneNode(bool deep) const = 0;
 
    virtual void normalize() = 0;
 
    virtual bool isSupported(const stringT& feature, const stringT& version) const = 0;
 
    virtual const stringT& getNamespaceURI() const = 0;
    virtual const stringT& getPrefix() const = 0;
    virtual void setPrefix(const stringT& prefix) = 0;
    virtual const stringT& getLocalName() const = 0;
 
    // additional methods - since C++ std::string (and by implication
    // stringT) don't differenciate between a null string and an empty string,
    // but the DOM recommendation does, I have to introduce these three methods 
    // to disambiguate.  If they return false, the corresponding attribute should be
    // considered null.  If they return true, the attribute has been set EVEN IF 
    // it has been set to the empty string
    virtual bool hasNamespaceURI() const = 0;
    virtual bool hasPrefix() const = 0;
 
    virtual bool hasAttributes() const = 0;
}; // class Node_impl
Вообщем-то либа представляет возможность именно пользователю реализовать при желании свою имплементацию на базе интерфейсов библиотеки (хотя тогда пользователь перейдет в разряд разработчика).
Bers
Заблокирован
24.11.2011, 11:58     Классы-посредники #14
Цитата Сообщение от ForEveR Посмотреть сообщение
хотя тогда пользователь перейдет в разряд разработчика
Это ключевой момент)

Просто кто-то заранее позаботился, как потом можео будит безболезненно расширять и развивать библиотеку. Вот только расширением этим будут заниматься кто? Правильно, сами разработчики библиотеки, а не конечные пользователи)

К самим пользователям библиотеки это отношения уже иметь не должно.
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
24.11.2011, 12:01     Классы-посредники #15

Не по теме:

Цитата Сообщение от Bers Посмотреть сообщение
Пользователи только пользуются. Они ничего не дорабатывают.
а почему слово пользователь моментально ассоциируется с конечным пользователем?
Программист, использующий интерфейс абстрактных классов, - не пользователь?



Цитата Сообщение от Bers Посмотреть сообщение
Правда есть один фокус, как можно использовать идиому pImpl, но при этом не использовать new delete. Гм... в общем то фокус этот я "изобрел" сам, но до ума его так и не довел (времени тогда не хватило)
А можно суть, коротко?.. думается, всем любопытно стало.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.11.2011, 12:02     Классы-посредники #16
Bers, Ну не знаю... Я пользователь библиотеки впринципе... А допиливать приходится.
Bers
Заблокирован
24.11.2011, 12:16     Классы-посредники #17
Цитата Сообщение от BRcr Посмотреть сообщение
А можно суть, коротко?
Правилами форума запрещено кидать линки на "порталы-конкуренты".
А заново выкладывать сырую технику rImpl уже здесь мне не хочется.
Ибо она действительно представляет угрозу, при неправильном использовании. И сулит больше проблем, чем профита.

Её нужно сначала допилить, что бы инструмент был безопасен, удобен, и практичен.
И только потом уже выкладывать готовую рабочую версию.

То есть, я не хочу по второму разу наступать на одни и теже граблни. Если будит у меня время - доведу идею до ума, тогда конечно выложу) А так могу кинуть линк на обсуждение сырой ещё идеи, но только по личке.

Добавлено через 2 минуты
Цитата Сообщение от BRcr Посмотреть сообщение
Программист, использующий интерфейс абстрактных классов, - не пользователь?
Программист, который использует в своих разработках вектора STL является пользователем библиотеки STL.

Он же не допиливает готовый продукт в виде всяких там векторов под свои конкретные нужды.
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
24.11.2011, 12:24     Классы-посредники #18
Цитата Сообщение от Bers Посмотреть сообщение
Программист, который использует в своих разработках вектора STL является пользователем библиотеки STL.
Он же не допиливает готовый продукт в виде всяких там векторов под свои конкретные нужды.
почему нет? имплементирует и допилит, коли нужда припрет
Bers
Заблокирован
24.11.2011, 12:52     Классы-посредники #19
Цитата Сообщение от BRcr Посмотреть сообщение
почему нет? имплементирует и допилит, коли нужда припрет
Потому что перфоратор служит для того, что бы долбить в стенке дыры.
А электро-дрелька - для того, что бы сверлить в стенке дырки.

Если же вы берете в руки готовую рабочую дрель, и разбираете её на запчасти, что бы собрать из неё перфоратор, значит либо что-то не в порядке у вас с головой, либо что-то не порядке с вашим проектом.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.11.2011, 13:31     Классы-посредники
Еще ссылки по теме:

C++ Классы
C++ классы

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
24.11.2011, 13:31     Классы-посредники #20
а если
Цитата Сообщение от Bers Посмотреть сообщение
мы берем в руки готовую рабочую дрель
, убираем кнопку непрерывного сверления(мешает иногда и не нужна никогда) и прикручиваем к ней миниатюрный уровень, чтоб сверлить ровно, у нас с головой все, надеюсь, в порядке?
Потому что с одной дрелькой я уже такое проделал. Я беспокоюсь за свою голову.
Yandex
Объявления
24.11.2011, 13:31     Классы-посредники
Ответ Создать тему
Опции темы

Текущее время: 00:50. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru