Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Концепция "Pointer to Implementation", С нюансами использования protected части 
:(
    Опции темы
EvilsInterrupt
Дата 19.1.2010, 01:38 (ссылка)    | (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



Вероятно все сталкивались с методикой pointer to impl, пример приведу тут:

содержимое инклуда stack.h:
Код

class c_stack {
  struct link;
  link * head;
public:
  void initialize();
  void push(void * data);
  void *peek();
  void *pop();
  void cleanup();
};


содержимое файла-реализация stack.cpp:
Код

struct c_stack::link{
  void * data;
  link * next;
  void initialize(void * dat, link * nxt);
}*head;

void c_stack::link::initialize(void *dat, c_stack::link *nxt)
{
  data = dat;
  next = nxt;
}

void c_stack::initialize() { head = 0; }

void c_stack::push(void *data)
{
  link * new_link = new link;
  new_link->initialize(data,head);
  head = new_link;
}


Это куски из примера ). В чем тут прикол, а то что заказчик лишен возможности видеть хоть какую-либо реализацию!!! Даже структура скрыта в файле-реализации. В случае private части класса, все логично и понятно!
А что делать если это касается protected части базового класса ? Ведь потомок захочет вдруг воспользоваться тем что в protected части, а оно если следовать методике p-to-impl скрыто! Как быть ?

Открывать ? Тогда : 1) заказчик больше получит информацию о строении либы 2) при изменении хоть чего-то в реализации, это еще одна перекомпиляция проекта, а так сделал интерфейс и меняй себе реализацию скольо хочешь!

Как быть с protected частью базового, чтобы было доступно потомкам его и при этом скрыто от заказчика библиотеки классов ? )
PM MAIL WWW ICQ Jabber   Вверх
mes
Дата 19.1.2010, 02:05 (ссылка) |    (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(EvilsInterrupt @  19.1.2010,  00:38 Найти цитируемый пост)
Вероятно все сталкивались с методикой pointer to impl,

ну тут PImpl`ом и не пахнет .. простое АТД.
Цитата(EvilsInterrupt @  19.1.2010,  00:38 Найти цитируемый пост)
А что делать если это касается protected части базового класса ? Ведь потомок захочет вдруг воспользоваться тем что в protected части, а оно если следовать методике p-to-impl скрыто! Как быть ?

а вот тут не понятно в чем проблема. Хотите чтоб было доступно ? ну так сделайте.. не хотите не делайте smile

Добавлено через 1 минуту и 18 секунд
чего то я в примере не найду ничего protected`ного..


--------------------
PM MAIL WWW   Вверх
kemiisto
  Дата 19.1.2010, 11:07 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дикий Кот. =^.^=
****
Награды: 1



Профиль
Группа: Участник Клуба
Сообщений: 3292
Регистрация: 29.7.2007

Репутация: 2
Всего: 160



Цитата(mes @  19.1.2010,  03:05 Найти цитируемый пост)
ну тут PImpl`ом и не пахнет .. простое АТД.

+1 Только таки простой АТД. ;-)

Цитата(EvilsInterrupt @  19.1.2010,  02:38 Найти цитируемый пост)
А что делать если это касается protected части базового класса ?

Он ты как захотел. smile Смотри, что умные дядьки пишут.
Цитата
 - put all private and protected members into XImpl;

Taking this extra step is actually wrong. Protected members should never go into a pimpl, since putting them there just emasculates them. After all, protected members exist specifically to be seen and used by derived classes, and so aren't nearly as useful if derived classes can't see or use them.


Тут ведь в чём дело. С точки зрения современного ОО проектирования в вершине иерархии классов должен стоять либо интерфейс, либо абстрактный класс. Строго говоря, в Це++ нет ни того, ни другого. smile Но мы тут не об этом. Так вот у этого чисто абстрактного класса нет реализации по определению. И тут уже pimpl идёт лесом.

Ну и дальше там будет неувязочки
Цитата
I believe the main drawback is that the pimpl object cannot call a virtual method of the main object without a back pointer. Since the objective of this approach is to avoid the use of a back pointer, it cannot be very useful if your class has virtual methods that need to be called in its implementation (which is usually the case with inheritance) thereby requiring a back pointer.


А всё почему? Прально! smile Ну нет модулей в языке! Нет и не будет. smile 


--------------------
PM MAIL WWW GTalk Jabber   Вверх
baldina
Дата 19.1.2010, 13:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



EvilsInterrupt, обобщая сказанное mes и kemiisto: можно впихнуть невпихуемое и совместить pimpl с абстракцией. но они будут на разных уровнях иерархии.

Например, вверху иерархии абстрактный стек:

Код

// stack.h

template <typename T>
class stack {
  
  protected:
    virtual size_t size () const = 0;
    virtual size_t capacity () const = 0;
    virtual void reserve (size_t) = 0;
    virtual void add (const T&) = 0;
    virtual void remove () = 0;
    virtual T get () const = 0;

  public:
    T top () const { return get(); }
    void pop() { remove(); }
    void push (const T& x) { add(x); }
    bool is_empty () const { return size() == 0; }
    virtual ~stack() {}
  
};

// конкретная реализация может переопределять защищенные члены и использовать pimpl
// vstack.h
#include <memory>
#include "stack.h"

template <typename T>
class vstack: public stack<T> {
  private:
    class vector;
    std::auto_ptr<vector> p_impl;

  protected:
    virtual size_t size () const;
    virtual size_t capacity () const;
    virtual void reserve (size_t size);
    virtual void add (const T& x);
    virtual void remove ();
    virtual T get () const;
  
  public:
    vstack ();
    ~vstack ();
};


клиентский код видит и использует только то, что ему положено:

Код

#include <iostream>
#include "vstack.h"

template <typename T>
void print_stack (stack<T>& s)
{
  while (!s.is_empty ())
  {
    std::cout << s.top () << ' ';
    s.pop ();
  }
}

int main ()
{
  vstack <int> s;
  for (int i=0; i < 10; ++i)
    s.push (i);
  print_stack (s);
}


реализация произвольна, например стандартный вектор

Код

// vstack_impl.h
#include <vector>
#include "vstack.h"

template <typename T>
class vstack<T>::vector : public std::vector<T> {};

template <typename T>
vstack<T>::vstack () : p_impl( new vstack<T>::vector ) {}

template <typename T>
vstack<T>::~vstack () {}

template <typename T>
size_t vstack<T>::size () const 

  return p_impl->size(); 
}

template <typename T>
size_t vstack<T>::capacity () const

  return p_impl->capacity(); 
}

template <typename T>
void vstack<T>::reserve (size_t size)

  p_impl->reserve (size); 
}

template <typename T>
void vstack<T>::add (const T& x)

  p_impl->push_back (x); 
}

template <typename T>
void vstack<T>::remove ()

  p_impl->pop_back(); 
}

template <typename T>
T vstack<T>::get () const

  return *--p_impl->end(); 
}


ЗЫ: если где нить инстанциировать шаблон, оно даже возможно заработает  smile 
типа
Код

#include "st_impl.h"
template vstack <int>;

PM MAIL   Вверх
EvilsInterrupt
Дата 19.1.2010, 19:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



И тем не менее, то что я привел называется Pimpl, вот по этому паттерну статья
или еще одна .
В том что я привел в хидере объявляется указатель на структуру, которая всего-лишь объявлена, но определена в файле реализации! Это вполне удовлетворяет идее паттерна!

Почему собственно возникла такая ситуация ? 
1) Дело в том, что пользователя должно заботить только то что в паблик части, он это хотел, он это получил!
2) Проект может быть связан с системами компьютерной безопасности, зачем пользователю показаывать лишний раз детали, которые его абсолютно не касаются?
3) Если хидер описан умело, то не изменяя его, а только файлы реализации, то можно не боятся, что придется весь проект перекомпиливать !
4) В среде разработке, когда пишешь код с применением code complition в комбобоксе также показывается и приват и протектед часть, нафига она мне пользователю класса нужна ?

С private часть все понятно, но с protected тоже не мешало бы скрыть от юзера, как  это сделать ?
PM MAIL WWW ICQ Jabber   Вверх
zim22
Дата 19.1.2010, 19:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(EvilsInterrupt @  19.1.2010,  18:23 Найти цитируемый пост)
С private часть все понятно, но с protected тоже не мешало бы скрыть от юзера, как  это сделать ?

мда... kemiisto вроде всё сказал уже:
Цитата(kemiisto @  19.1.2010,  10:07 Найти цитируемый пост)
 - put all private and protected members into XImpl;

Taking this extra step is actually wrong. Protected members should never go into a pimpl, since putting them there just emasculates them. After all, protected members exist specifically to be seen and used by derived classes, and so aren't nearly as useful if derived classes can't see or use them.


 

Это сообщение отредактировал(а) zim22 - 19.1.2010, 19:34


--------------------
PM MAIL   Вверх
baldina
Дата 19.1.2010, 19:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата

1) заказчик больше получит информацию о строении либы

Если заказчик будет наследовать классам либы, то ему, возможно, понадобится дополнительно знание о её строении. Тут все ок.
Если заказчик НЕ  будет наследовать классам либы, то protected данные в классах, видимых заказчику, вообще не нужны.


PM MAIL   Вверх
mes
Дата 19.1.2010, 19:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(EvilsInterrupt @  19.1.2010,  18:23 Найти цитируемый пост)
И тем не менее, то что я привел называется Pimpl, вот по этому паттерну статья
или еще одна .

ну вот цитата из Вашей статьи :
Цитата

Каждый метод, который содержит доступ к приватной реализации добавляет плюс одну экстра инструкцию.

можете показать где такое в Вашем примере ? 
 smile 

Цитата(EvilsInterrupt @  19.1.2010,  18:23 Найти цитируемый пост)
В том что я привел в хидере объявляется указатель на структуру, которая всего-лишь объявлена, но определена в файле реализации! Это вполне удовлетворяет идее паттерна!

удовлетворяет - не значит достаточно smile 

Ну а по теме: все зависит от Ваших условий - сформулируйте их для себя.. что позволено клиенту и до какой степени и это будет ответом на вопрос какую из идеологий  (или какой диалект идиологии) выбрать для Вашего случая.



Это сообщение отредактировал(а) mes - 19.1.2010, 20:03


--------------------
PM MAIL WWW   Вверх
EvilsInterrupt
Дата 19.1.2010, 20:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



Цитата

Если заказчик НЕ  будет наследовать классам либы, то protected данные в классах, видимых заказчику, вообще не нужны.

Вот и я о том, но возьмем к примеру ситуацию :

0) животное - базовый класс
1.1) Тигр от животного
1.2) Собака от животного

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

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

Как быть-то программеру ? Как спрятать защищенные методы вынесенные в базовый? Может их  тупо убрать и кинуть в потомки?! Однако это не следование ООП-мысли !!! ;)
PM MAIL WWW ICQ Jabber   Вверх
zim22
Дата 19.1.2010, 21:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(EvilsInterrupt @  19.1.2010,  19:33 Найти цитируемый пост)
Однако это не следование ООП-мысли !!! ;)

ООП-мысль - это что?

кстати, наследование нарушает инкапсуляцию. (GoF)


--------------------
PM MAIL   Вверх
mes
Дата 20.1.2010, 00:23 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(EvilsInterrupt @  19.1.2010,  19:33 Найти цитируемый пост)
Как быть-то программеру ? Как спрятать защищенные методы вынесенные в базовый? Может их  тупо убрать и кинуть в потомки?! Однако это не следование ООП-мысли !!! ;) 

1. Не делать защищенные методы в классах не предназначенных для наследования
2. Не давать пользователю, то что ему не нужно
3. Не искать прямых путей - обходной может быть короче.

Итого пользователю нужно :
1. интерфейс животного -> абстрактный класс с открытыми методами.
2. Два наследника этого -> два класса реализующих этот интерфейс с отсутсtвием лишних деталей.
Разработчик реализует :
1. Описание ползовательских классов (include/animals.h)
2. Набор функций/ классов реализующих общее и индивидуальное поведение  (source/animals_detail.h)
3. Связь пользовательских классов с функциональностью (source/animals.cpp) 

smile





--------------------
PM MAIL WWW   Вверх
bsa
Дата 20.1.2010, 12:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



EvilsInterrupt, как вариант можно сделать два класса-обертки, конструкторы/деструкторы которых будут создавать/уничтожать реализацию, которая, в свою очередь, может быть какой угодно (хоть все методы виртуальные и открытые). Вот в этом случае и будет настоящий PIMPL - класс "тигр" будет содержать только указатель на класс TigerImpl, реализация которого будет исключительно внутри библиотеки, и доступные методы. smile
PM   Вверх
baldina
Дата 20.1.2010, 12:40 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



EvilsInterrupt
Цитата

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

Вы неправильно ставите задачу. Вы все время думаете о реализации, а начинать надо с постановки цели. Когда есть цель, можно искать средства реализации. Если цели нет, то можно наплодить кучу реализаций, но их практическая ценность будет близка к нулю.
PM MAIL   Вверх
EvilsInterrupt
Дата 20.1.2010, 18:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Executables research
***


Профиль
Группа: Завсегдатай
Сообщений: 1019
Регистрация: 14.7.2007
Где: Железнодорожный, МО, Россия

Репутация: 2
Всего: 9



2 baldina :
>>Вы неправильно ставите задачу. 
Ну неужели я должен тут постить ситуацию заказчика ? Все его секреты и заскоки ? ИМХО, не имею права! Потому и придумываю ситуацию похоже на его!

Ситуация проста, он хочет получить интерфейс и файл библиотеки, а я нехочу чтобы он хоть чтото знал о том как реализована. Малейшая мысль о том как сделано, сведет на нет работу, а lib-файл покрою протом, это же обыкновенный x86-код и формат не шибко отличается от тех PE-заморочек в привычных нам exe, dll, sys файлах!!!

Пока пришел к выводу:
1) Создаю в инклуд базовый класс и + инструкцию которая в аргументе возвращает созданный объект потомка, ну и bool, как возвращаемое значение ф-ции.
2) В файлах реализации создаю потомки этого базового класса, ну и там же наследуюсь в еще один класс промежуточный class c_wrapper_animal : public c_basic_animal
3) В промежуточном  c_wrapper_animal создаю все протектед методы, которые переопределяю и реализовываю в потомках
4) Реальные объекты создаются в зависимости от аргумента "at" функции bool create_animal(c_basic_animal * animal, animal_type at) , именно существование этой ф-ции упомяналось в п.1.

Дальше компилю, протечу(защищаю протектором) и высылаю animal.h + animal.lib , на этом пока мои мысли завершены.

Собственно пока на этом все!
PM MAIL WWW ICQ Jabber   Вверх
maxim1000
Дата 20.1.2010, 18:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 17
Всего: 110



если у нас есть три набора информации, у каждой из которых разные пользователи, логично поместить её в три файла:

в основном h-файле - информация для всех пользователей: описание класса, указатель на структуру с private-данными, указатель на структуру с protected-данными

в дополнительном h-файле - информация для тех, кто захочет наследоваться: описание структуры с protected-данными основного класса

в третьем файле (cpp или ещё один h) - информация для внутренней реализации класса: описание структуры с private-данными основного класса

тогда каждый подключает тот файл, который ему нужен



--------------------
qqq
PM WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1003 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.