Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > shared_ptr и abstract factory


Автор: fear 1.3.2010, 18:59
Хочу создать фабрику, которая будет создавать объекты и возвращать shared_ptr на них.
Предпологается что создаваемый объект будет использоваться внутри фабрики и в случае необходимости и вне ее, когда необъодимость в нем исчезнет, память им занимаемая освободиться.

Реализация могла бы быть следующая, только метод create() должен быть виртуальным smile кто подскажет как решить задачу? Фабрика не должна быть шаблоном smile

Код

#include <boost/shared_ptr.hpp>
#include <iostream>

class A
{
  public:
    virtual int func() { return 1; }
};

class B: public A
{
  public:
    virtual int func() { return 2; }
};

class AF
{
  public:
    boost::shared_ptr<A> create() {
      return boost::shared_ptr<A>(new A);
    }
};

class BF: public AF
{
  public:
    boost::shared_ptr<B> create() {
      return boost::shared_ptr<B>(new B);
    }
};

int main()
{
  AF *factory = new BF;
  boost::shared_ptr<A> a = factory->create();
}


Автор: azesmcar 1.3.2010, 19:08
Странная фабрика какая-то, и вообще зачем нужно это? Полиморфизм на что придумали, фабрика должна возвращать указатель на базовый класс, и базовый класс должен давать достаточно богатый интерфейс, чтобы использовать его функциональность.

Вот пример реализации фабрики
http://forum.vingrad.ru/forum/topic-266893/hl/factory/0.html

Автор: fear 1.3.2010, 19:16
AF и ВF  не совсем фабрика smile
это некие классы которые предназначены для создания в себе объектов классов A и B соответственно и только их
возвращать они должны указатели на управляемые ими объекты

по ссылке счас схожу

Автор: azesmcar 1.3.2010, 19:19
Цитата(fear @  1.3.2010,  19:16 Найти цитируемый пост)
это некие классы которые предназначены для создания в себе объектов классов A и B соответственно и только их

скромный вопрос, а зачем это нужно? smile для этого надо класс создавать? оператор new не подходит?

Автор: fear 1.3.2010, 23:01
azesmcar, давайте про полиморфизм лучше поговоим )))

В данном примере неизменно следующее:
Код

struct I {};
struct A: I {};
struct B: I {};


далее у нас появляется некая фабрика (пусть все же фабрикой будет smile ) и ее наследники
Код

struct F {};
struct AF: F {};
struct BF: F {};


каждый из наследников создает экземпляр некоторого класса:
Код

struct F {
  virtual I *create() = 0;
};

struct AF {
  A *create();
};

struct BF {
  B *create();
};


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

struct F {
  virtual boost::shared_ptr<I> create() = 0;
};

struct AF {
  boost::shared_ptr<A> create();
};

struct BF {
  boost::shared_ptr<B> create();
};


а так хочется ))) чтобы умные указатели вели себя аналогично глупым стандартным smile

Автор: mes 2.3.2010, 12:54
Цитата(fear @  1.3.2010,  22:01 Найти цитируемый пост)
давайте про полиморфизм 

Цитата(fear @  1.3.2010,  22:01 Найти цитируемый пост)
чтобы умные указатели вели себя аналогично 

поможет паттерн bridge, проявление которого может быть как минимум в двух вариантах, хоть и одинаковых по сути : 
 изменить классы под идиологию PImpl  или создать адаптер контролирующий cloneable-поведение доверенного объекта

Автор: SenkraD 2.3.2010, 13:00
fear,  ну могу сказать:
   - возвращайте указатели на классы и после ретурна вяжите их в smart_ptr
   - возвращайте boost::shared_ptr<I> и если нуно поработать как с потомком,
     то юзайте boost::shared_polymorphic_downcast
   - может подойдёт CRTP?

Автор: SenkraD 2.3.2010, 13:32
[offtop]mes,  я онимаю зачем адаптер и в принципе поддерживаю,
но я не совсем понял как тут Pimpl поможет?[/offtop]

Автор: mes 2.3.2010, 13:49
Цитата(SenkraD @  2.3.2010,  12:32 Найти цитируемый пост)
но я не совсем понял как тут Pimpl поможет

так же, касательно этой темы по сути одно и то же, просто взгляд с разных сторон.
Нам надо разделить обязанности на  две роли :
1. полиморфное поведение 
2. копирование на основе клонирования
в случае с адаптером сам объект выполняет первую роль, а адаптер вторую.
в pimpl же объекту достается 2я роль, а за поведение отвечает имплементация.

 

Автор: fear 2.3.2010, 16:15
Цитата

- возвращайте указатели на классы и после ретурна вяжите их в smart_ptr

фабрика F создает объект I, один указатель на него она хранит у себя (чтобы работать с объектом); второй отдает наружу (если в нем есть необъодимость); поэтому и используются shared_ptr и поэтому вязать снаружи нельзя, ну или не красиво

Цитата

- возвращайте boost::shared_ptr<I> и если нуно поработать как с потомком, то юзайте boost::shared_polymorphic_downcast

на этот вариант пока что и ставка

Цитата

- может подойдёт CRTP? 

что это? ))

mess, можете привести пример кода как в данном случае может помоч pimpl или bridge?

Автор: SenkraD 2.3.2010, 16:33
fear, звини щас накидать тебе под твоё времени нет,
но ты пока почитай http://rsdn.ru/forum/cpp/2674420.aspx и http://rsdn.ru/forum/cpp/2677311.aspx и если не разберёшся, то маякуй подумаем вместе

Автор: fear 2.3.2010, 16:38
mess, речь о чем то похожем?

Код

template <typename T>
struct Y
{
    T create() = 0;
};

template <typename T, typename Factory>
struct X: Y<T>
{
    X() :f(new Factory) {}
    T create() {
      return f->create();
    }
    
    Factory *f;
};

struct AF: Y<A>
{
    boost::shared_ptr<A> create() {...};
};

struct AF: Y<B>
{
    boost::shared_ptr<B> create() {...};
};


все хорошо, но мне нужен не шаблонный базовый класс фабрики

Автор: mes 2.3.2010, 17:11
Цитата(fear @  2.3.2010,  15:38 Найти цитируемый пост)
но мне нужен не шаблонный базовый класс фабрики 

Ну прежде всего Вы не там сконцентрировали внимание.. проблема у Вас не в фабрике, а в shared_ptr для полиморфного объекта..
т.е. в shared_ptr<Base> вы не можeте хранить полиморфнo например  объект Derived.

что то в торопях глупость сморозил.. 
Добавлено @ 17:13
Цитата(fear @  2.3.2010,  15:15 Найти цитируемый пост)
mess

Вобще то mes, без всяких двойных ss иначе из моего ника получается беспорядок  smile 

Автор: SenkraD 2.3.2010, 17:20
Цитата(mes @  2.3.2010,  17:11 Найти цитируемый пост)
т.е. в shared_ptr<Base> вы не можeте хранить полиморфнo например  объект Derived.
Это почему вдруг? - Нормально он с полиморфными обьектами работает.

fear,  у тебя фабрика создает обьект, потом тебе его нужно отконфижить
и прокинуть дальше, а потом с ним работают через интерфейс базового класса?
Или у тебя есть перегруженные функции, которым передаются результат фабричного
метода
Код
void foo(A*);
void foo(b*);

// и где-то в коде
foo(someConcreteFactory.create());
?

Автор: mes 2.3.2010, 17:21
...

Автор: mes 2.3.2010, 18:50
Цитата(fear @  2.3.2010,  15:15 Найти цитируемый пост)
как в данном случае может помоч pimpl или bridge

слишком мало деталей Вы сказали, но для приведенной немного выше проблемы, могло быть такое решение  :
Код


struct A {};
struct B {};

struct I { virtual ~I() {} };
struct AW : I { shared_ptr<A> Impl_; };
struct BW : I { shared_ptr<B> Impl_; };

struct IF      {  virtual I&  Create (); };
struct AF : IF {          AW& Create (); };
struct BF : IF {          BW& Create (); };


Автор: Леопольд 2.3.2010, 19:20
Цитата(SenkraD @  2.3.2010,  17:20 Найти цитируемый пост)
Цитата(mes @  2.3.2010,  17:11 Найти цитируемый пост)
т.е. в shared_ptr<Base> вы не можeте хранить полиморфнo например  объект Derived.
Это почему вдруг? - Нормально он с полиморфными обьектами работает

Честно говоря я тоже не понял, почему. shared_ptr просто обёртка над обычным указателем. Главное что-бы базовый класс(интерфейс) имел открытый виртуальный деструктор...

Добавлено @ 19:33
Всё же PIMPL это вот так:

header.hpp
Код
#include <boost/shared_ptr.hpp>

struct Type{
    Type(int);
    int getField();
private:
    struct Impl;
    boost::shared_ptr<Impl> pImpl_;
};


source.cpp
Код

#include "header.hpp"

struct Type::Impl{
    Impl(int f): field(f) {}
    int field;
};

Type::Type(int i): pImpl_(new Impl(i)) {}

int Type::getField(){
    return pImpl_->field;
}


usercode.cpp
Код
//...
     x = obj.getField();
//...


В результате, в usercode.cpp, даже компилятор не видит имена из Impl. Полноценная инкапсуляция.

Автор: mes 2.3.2010, 19:48
Цитата(Леопольд @  2.3.2010,  18:20 Найти цитируемый пост)
Честно говоря я тоже не понял, почему. shared_ptr просто обёртка над обычным указателем.

я ж исправился там (перечеркнул)  smile 

Цитата(Леопольд @  2.3.2010,  18:20 Найти цитируемый пост)
Всё же PIMPL это вот так:

если применительно к моему примеру, то там акцент не на демонстрацию технологии PImpl smile


Автор: Леопольд 2.3.2010, 22:41
Цитата(mes @  2.3.2010,  19:48 Найти цитируемый пост)
я ж исправился там (перечеркнул) 

Это всё моя невнимательность  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)