Задача по проектированию шаблонов
От: creatio Украина  
Дата: 24.04.03 09:02
Оценка:
Есть класс

class    FEAXControl {
public:
FEAXControl(pFEInter inInter):FEBaseObject(inInter) {}
virtual    ~FEAXControl();
};


В момент инициализации приходит IUnknown* у которого запрашиваем набор интерфейсов из которых поддерживается только один.

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

Очень не хочется кучу проверок ставить (чтобы определить где лежит проинициализированный указатель) и кучу обёрток на интерфейсы писать (с общим базовым классом) тоже не хочется (их в дальнейшем может потребоваться добавлять не ограниченное количество), а в проектировании шаблонов пока опыта маловато.

Как бы лучше поступить?
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 24.04.03 12:07
Оценка:
Вот то что пришло на ум. Но оно есесно не работает (под VC 6.0 SP5)


template<const IID* piid=__uuidof(T)>
struct B {
    IUnknown* m_pIcontrol;
};

template<>
struct B<&IID_IMyInterface
    IClassFactory* m_pIcontrol; 
};

// ... и так далее для других IID_IXXX

class BUser {
public:
    template<const IID* piid> B<piid> Get() {return B<piid>;}
    B* b;
};

Использование:

int main(int argc, char* argv[])
{
    IUnknown *pUnk=0;
    BUser busr;
//не компилится с сообщением: left of '.m_pIcontrol' must have class/struct/union type
    busr.b.m_pIcontrol->Addref();
//не компилится с сообщением: error C2059: syntax error : ')'
    busr.b.Get<&IID_IUnknown>().m_pIcontrol->AddRef(); 
    return 0;
}


Сразу скажу, что на не инициализированные указатели пока вообще не смотрим — компилятор бы научить задачу понимать...
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re: Задача по проектированию шаблонов
От: ssm Россия  
Дата: 25.04.03 13:33
Оценка:
Здравствуйте, creatio, Вы писали:

Несовсем понятно чего ты хочешь, этого?

template<typename T>
class    FEAXControl {
  T * FEBaseObject;
public:
FEAXControl(T * inInter):FEBaseObject(inInter) {}
virtual    ~FEAXControl();
};
Re: Задача по проектированию шаблонов
От: Bell Россия  
Дата: 25.04.03 13:39
Оценка:
Здравствуйте, creatio, Вы писали:

Информации явно недостаточно.
Как связаны между собой интерфесы из твоего набора?
Различается ли у них набор методов?
Каким образом будет работать система после получения определенного интерфейса? Т.е. повлияет ли то, какой именно интерфейс получен, на дальнешие действия?
И т.д.

Переформулируй свою задачу, опиши чего ты хочешь добиться в финале.
И тогда навенряка...
Любите книгу — источник знаний (с) М.Горький
Re[2]: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 25.04.03 14:01
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>Здравствуйте, creatio, Вы писали:


ssm>Несовсем понятно чего ты хочешь, этого?

В единственной переменной-члене должен храниться указатель на пришедший интерфейс.
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re[3]: Задача по проектированию шаблонов
От: ssm Россия  
Дата: 25.04.03 14:05
Оценка:
Здравствуйте, creatio, Вы писали:

C>Здравствуйте, ssm, Вы писали:


ssm>Здравствуйте, creatio, Вы писали:


ssm>Несовсем понятно чего ты хочешь, этого?

C>В единственной переменной-члене должен храниться указатель на пришедший интерфейс.

Тогда используй то чего я тебе написал, или храни IUnknown*. Что ты потом хочешь делать с этим классом?
Re[2]: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 25.04.03 14:17
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, creatio, Вы писали:


B>Как связаны между собой интерфесы из твоего набора?

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

B>Различается ли у них набор методов?

Есть общий набор, есть и специфичные методы.

B>Каким образом будет работать система после получения определенного интерфейса? Т.е. повлияет ли то, какой именно интерфейс получен, на дальнешие действия?

Нет. Просто вызываем общий метод.

B>Переформулируй свою задачу, опиши чего ты хочешь добиться в финале.

Попробую.
Получаю указатель на интерфейс (объект класса), который надо сохранить и для него вызывать его собственные методы (сам класс используется только для внутренних нужд некоторого контейнера)...
ну или так:

Есть интерфейсы
interface IUnknown {
  long UMethode1()=0;
  long UMethode2()=0;
  long UMethode3()=0;
};

interface IFace1 : public IUnknown {
  long Methode1()=0;
  long Methode2()=0;
  long Mtd1()=0;
};
interface IFace2 : public IUnknown {
  long Methode1()=0;
  long Methode2()=0;
  long Mtd2()=0;
};
interface IFace3 : public IUnknown {
  long Methode1()=0;
  long Methode2()=0;
  long Mtd3()=0;
};
//и могут и будут добавляться в дальнейшем аналогично выглядящие

class    FEAXControl {//Класс оболочка
  Какой_то_тип* FEBaseObject;  //Очень хочется здеcь сохранять указатель 
                           //на один из этих интерфейсов, чтобы потом вызывать методы
                           //вызов будет снаружи этого класса
public:
  FEAXControl(T * inInter):FEBaseObject(inInter) {}
  virtual    ~FEAXControl();
};


Исправлена подсветка синтаксиса. -- ПК.
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re[4]: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 25.04.03 14:26
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>Тогда используй то чего я тебе написал, или храни IUnknown*. Что ты потом хочешь делать с этим классом?

Не то ни другое непосредственно не подходит — Тип определяется на этапе выполнения, IUnknown надо кастить к типу, который оказывается известным только на этапе выполнения.
Беда усугубляется ещё и тем, что нельзя выстраивать кучу проверок, чтобы определить где нужный указщатель лежит — очень медленно получается.
т.е.

class A {
  IFace1* if1;
  IFace1* if2;
  IFace1* if3;

  f(IID iid) {
  if(iid==iid_if1)
   if1 = src_iface;
  if(iid==iid_if2)
   if2 = src_iface;
  if(iid==iid_if3)
   if3 = src_iface;
}

if_Methode1() {
if(if1) {
   if1->Methode1();
   return;
   }
if(if2) {
   if2->Methode2();
   return;
   }
if(if3) {
   if3->Methode3();
   return;
   }
}

if_Methode2() {  
// ...
}
}; //END_CLASS_DEF


Вообщем, думаю, не надо объяснять, что так плохо
А вот как — хорошо?

Исправлена подсветка синтаксиса. -- ПК.
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re[5]: Задача по проектированию шаблонов
От: MaximE Великобритания  
Дата: 25.04.03 14:30
Оценка:
Здравствуйте, creatio, Вы писали:

[]

C>Вообщем, думаю, не надо объяснять, что так плохо

C>А вот как — хорошо?

Рассмотри паттерн "стратегия" (Strategy).
Re[5]: Задача по проектированию шаблонов
От: ssm Россия  
Дата: 25.04.03 14:32
Оценка:
Здравствуйте, creatio, Вы писали:

C>Вообщем, думаю, не надо объяснять, что так плохо

C>А вот как — хорошо?

Хорошо, это когда у тебя метод виртуальный есть у предка, но это тебе неподходит
Re[6]: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 25.04.03 14:33
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Рассмотри паттерн "стратегия" (Strategy).

С удовольствием, но только плиз намекните где он лежит. Я по части проектирования новичок. А с паттернами занком только понаслышке.
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re[6]: Задача по проектированию шаблонов
От: ssm Россия  
Дата: 25.04.03 14:35
Оценка:
Здравствуйте, MaximE, Вы писали:


ME>Рассмотри паттерн "стратегия" (Strategy).


Имеется в виду Visitor?
Re[6]: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 25.04.03 14:41
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>Хорошо, это когда у тебя метод виртуальный есть у предка, но это тебе неподходит

Ну... я кажется придумал решение
Ну неуверен, что оно самое лучшее (а если прикинуть на бесплодные поиски в тёмной долитне шаблонов ушли два рабочих дня...
Вот оно.

//Вот наши интерфейсы
struct A2 {virtual a2()=0;};
struct A3 {virtual a2()=0;};
//Компоненты реализующие их
struct B2 : public A2 {    a2() {std::cout<<"B2::a2()\n";}};
struct B3 : public A3 {    a2() {std::cout<<"B3::a2()\n";}};
//А вот оно! решение проблемы :)
struct my_bad_cast {};
struct Itype : 
public A2,
public A3
 {
a2() {throw my_bad_cast;}
virtual ~Itype();
};

int main(int argc, char* argv[])
{
    Itype* t=0;
    B2 *b = new B2();
    A2 *a_2 = b;

    t=reinterpret_cast<Itype*>(a_2);
        //t=dynamic_cast<Itype*>(a_2); //Жаль вот такое не работает
    t->a2();
    delete b;
}


Чёрт! Как всё просто оказалось!
Впрочем, может кто-то что-то красивее предложит?

Исправлена подсветка синтаксиса. -- ПК.
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re[7]: Задача по проектированию шаблонов
От: MaximE Великобритания  
Дата: 25.04.03 14:45
Оценка:
Здравствуйте, ssm, Вы писали:

ssm>Здравствуйте, MaximE, Вы писали:


ssm>

ME>>Рассмотри паттерн "стратегия" (Strategy).

ssm>Имеется в виду Visitor?


Стратегия. Тут у него большое количество условного кода. Стратегия предназначена как раз для решения этой проблемы.

Можно и Visitor. На мой взгляд, он более мощный и интересный, но и немного посложнее.
Re[7]: Задача по проектированию шаблонов
От: MaximE Великобритания  
Дата: 25.04.03 14:48
Оценка:
Здравствуйте, creatio, Вы писали:

C>Чёрт! Как всё просто оказалось!

C>Впрочем, может кто-то что-то красивее предложит?

Это работает по-случайности.

Опиши свою задачу более обще. Пока ничего непонятно.
Re[8]: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 25.04.03 15:07
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Это работает по-случайности.

Довольно неоднозначное заключение

ME>Опиши свою задачу более обще. Пока ничего непонятно.

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

Это проиллюстрировано в запостенном ранее исходнике.
Ну как умел...
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re[9]: Задача по проектированию шаблонов
От: MaximE Великобритания  
Дата: 25.04.03 16:02
Оценка: 9 (2)
Здравствуйте, creatio, Вы писали:

C>Тип указателя, который требуется сохранять, определяется на этапе выполнения.


Попробуй так:


#include <iostream>
#include <tchar.h>

////////////////////////////////////////////////////////////////////////////////////////////////

struct Visitor;

struct Visitable
{
    virtual void Accept(Visitor&) = 0;
    virtual ~Visitable() {}
};

struct Foo : Visitable
{
    virtual void FooMethod() = 0;
};

struct Bar : Visitable
{
    virtual void BarMethod() = 0;
};

struct Visitor
{
    virtual void Visit(Foo&) = 0;
    virtual void Visit(Bar&) = 0;
};

////////////////////////////////////////////////////////////////////////////////////////////////

template<class Interface>
struct VisitableImpl : Interface
{
    void Accept(Visitor& v)
    {
        v.Visit(static_cast<Interface&>(*this));
    }
};

class FooImpl : public VisitableImpl<Foo>
{
    void FooMethod() { std::cout << "Hi, I am Foo\n"; }
};

class BarImpl : public VisitableImpl<Bar>
{
    void BarMethod() { std::cout << "Hi, I am Bar\n"; }
};

Foo* CreateFoo() { return new FooImpl; }
Bar* CreateBar() { return new BarImpl; }

////////////////////////////////////////////////////////////////////////////////////////////////

struct InterfaceStrategy
{
    virtual void DoSome() = 0;
    virtual ~InterfaceStrategy() {}
};

template<class Interface>
struct InterfaceStrategyImpl;

template<>
struct InterfaceStrategyImpl<Foo> : InterfaceStrategy
{
    InterfaceStrategyImpl(Foo* i) : i_(i) {}
    void DoSome() { i_->FooMethod(); }
    Foo* i_;
};

template<>
struct InterfaceStrategyImpl<Bar> : InterfaceStrategy
{
    InterfaceStrategyImpl(Bar* i) : i_(i) {}
    void DoSome() { i_->BarMethod(); }
    Bar* i_;
};

struct InterfaceStrategyCreator : Visitor
{
    InterfaceStrategyCreator(InterfaceStrategy*& holder) : holder_(holder) {}

    void Visit(Foo& i) { holder_ = CreateHolder(i); }
    void Visit(Bar& i) { holder_ = CreateHolder(i); }

    template<class Interface>
        InterfaceStrategy* CreateHolder(Interface& i)
    {
        return new InterfaceStrategyImpl<Interface>(&i);
    }

    InterfaceStrategy*& holder_;
};

////////////////////////////////////////////////////////////////////////////////////////////////

class Wrapper
{
public:
    explicit Wrapper(Visitable* i)
    {
        InterfaceStrategyCreator c(holder_);
        i->Accept(c);
    };

    ~Wrapper() { delete holder_; }

    void Do() { holder_->DoSome(); }

private:
    InterfaceStrategy* holder_;
};

////////////////////////////////////////////////////////////////////////////////////////////////


int _tmain(int argc, _TCHAR* argv[])
{
    Foo* foo(CreateFoo());
    Bar* bar(CreateBar());

    Wrapper w1(foo);
    Wrapper w2(bar);

    w1.Do();
    w2.Do();

    delete bar;
    delete foo;

    return 0;
}
Re[10]: Задача по проектированию шаблонов
От: ssm Россия  
Дата: 29.04.03 06:03
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Попробуй так:


Думаю, что для знающего шаблон Visitor, код излишен, но для незнающего непомешало бы пару-тройку умных словес
Re[10]: Задача по проектированию шаблонов
От: creatio Украина  
Дата: 08.05.03 07:21
Оценка:
Здравствуйте, MaximE, Вы писали:

Наконец-то вернулся с вуходных
Вариант предложенный Вами, весьма крут и его даже удалось заставить компилиться на VC6 SP5 (правда заменив вызовы СreateFoo и CreateBar на явные вызовы new ).
Но хотелось бы немного прояснить некоторые детали, если позволите.

1. Вопервых, хотелось бы уточнить реализация какого паттерна была приведена (если таковой вообще использовался). Если можно, киньте, плиз, ссылку на мат.часть.
2. В данном решении, для добавления нового компонента потребуется довольно основательно покопаться в существующем коде (в моём случае возможно это придётся делать моему последователю).
Соответственно вопрос — есть ли какой-то другой вариант (другой паттерн?), при котором удобно было бы добавлять новые компоненты (т.е. с минимумом изменений готового кода)?

Заранее благодарен.
Why do you call Visual Studio 'your bunny'?...
(c) one american colleague
Re[11]: Задача по проектированию шаблонов
От: MaximE Великобритания  
Дата: 08.05.03 08:04
Оценка:
Здравствуйте, creatio, Вы писали:

C>1. Вопервых, хотелось бы уточнить реализация какого паттерна была приведена (если таковой вообще использовался). Если можно, киньте, плиз, ссылку на мат.часть.


Два паттерна: визитор и стратегия. Мат. часть — Design Patterns (русское издание "Шаблоны проектирования").

C>2. В данном решении, для добавления нового компонента потребуется довольно основательно покопаться в существующем коде (в моём случае возможно это придётся делать моему последователю).


Чтобы добавить еще одного Foo/Bar (далее Some) нужно:

1. Определить интерфейс Some, наследованый от Visitable.
2. Добавить в Visitor вирт. ф-цию Visit(Some& ).
3. Написать реализацию этого интерфейса Some (SomeImpl, наподобие FooImpl/BarImpl)
5. Написать ф-цию, которая создает объект SomeImpl (CreateSome).
6. Добавить специализацию стратегии InterfaceStrategyImpl<Some>, функция DoSome которой определяет действия, конкретные для данного интерфейса.
7. Добавить в InterfaceStrategyCreator еще одну ф-цию Visit(Some& ), точно такую же как и остальные Visit в этом классе.

C>Соответственно вопрос — есть ли какой-то другой вариант (другой паттерн?), при котором удобно было бы добавлять новые компоненты (т.е. с минимумом изменений готового кода)?


Думаю, что вполне возможно.

Это наиболее общая реализация. Для конкретной задачи можно придумать что-то более соответствующее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.