Интересный вопрос о декораторах на С++.
От: Germes Украина  
Дата: 08.11.10 18:55
Оценка: :))
class I_A
{
public:

    virtual void foo1() =0;
    virtual void foo2() =0;
    virtual ~I_A()
    {    }
};

class A : public I_A
{
public:
    virtual void foo1()
    {
        std::cout<<"foo:"<<"A"<<std::endl;
    }
    virtual void foo2()
    {
        std::cout<<"foo2:"<<"A"<<std::endl;
    }
};

template<typename T>
class foo2_decorator: virtual public T
{
    
public:
    typedef T base_type;

    foo2_decorator(const base_type& val):
        base_type(val)
    {
    }

    void foo2()
    {
        std::cout<<"foo2_decorator:"<<"foo2"<<std::endl;
    }
private:
};

template<typename T>
class foo1_decorator: virtual public T
{

public:
    typedef T base_type;

    foo1_decorator(const base_type& val):
    base_type(val)
    {
    }

    void foo1()
    {
        std::cout<<"foo1_decorator:"<<"foo1"<<std::endl;
    }
private:
};



int _tmain(int argc, _TCHAR* argv[])
{
    std::cout<<"-------------------------------"<<std::endl;
    A* p_A = new A;
    p_A->foo1();
    p_A->foo2();
    
    std::cout<<"-------------------------------"<<std::endl;
    p_A = new foo1_decorator<A>(*p_A);
    p_A->foo1();
    p_A->foo2();

    std::cout<<"-------------------------------"<<std::endl;
    p_A = new foo2_decorator<A>(*p_A);
    p_A->foo1();    
    p_A->foo2();

    std::cout<<"-------------------------------"<<std::endl;
    I_A* p_IA = p_A;
    p_IA->foo1();
    p_IA->foo2();



    return 0;
}


Output:
-------------------------------
foo:A
foo2:A
-------------------------------
foo1_decorator:foo1
foo2:A
-------------------------------
foo:A
foo2_decorator:foo2
-------------------------------
foo:A
foo2_decorator:foo2

Вопрос :
почему применение 2 декоратора отменяет действие первого ?
С уважением Germes!
Re: Интересный вопрос о декораторах на С++.
От: Vamp Россия  
Дата: 08.11.10 20:16
Оценка: +1
А что тебя, собственно, удивляет?
p_A = new foo2_decorator<A>(*p_A);

Теперь у тебя p_A указывает на объект типа foo2_decorator, в нем foo1 не переопределен. Как еще могло бы быть?
Да здравствует мыло душистое и веревка пушистая.
Re: Шарпист?
От: Erop Россия  
Дата: 08.11.10 20:43
Оценка:
Здравствуйте, Germes, Вы писали:

G>почему применение 2 декоратора отменяет действие первого ?

Потому, что ты не понимаешь, как в С++ работают виртуальные функции.
То, какая функция позовётся, определяется исключительно наиболее выведенным типом, а не полями объекта. Так что у типов A, foo1_decorator<A>, foo2_decorator<A> определены методы так, как они определены, вне связи с тем, каой там был аргумент конструктора!

Для того, чтобы применить оба, тебе надо было не аргументы в конструктор передавать, а юзать тип foo1_decorator<foo2_decorator<A> >

С другой стороны, если тебе хочется динамического связывания, то можно было прямо вот в A завести ПЕРЕМЕННЫЕ, в которых так или иначе хранить информацию о том, какой именно метод какого именно класса надо позвать.

Ну и вообще, обычно когда хочется смешать шаблоны и виртуальные методы, это обычно говорит, об ошибке дизайна.

Ещё можно было бы пойти оп такому пути:
class I_A
{
public:

    virtual void foo1() =0;
    virtual void foo2() =0;
    virtual ~I_A()
    {    }

    class decorator_base : public I_A 
    {
        decorator_base(I_A* сomponent ) : сomponent( сomponent )
        {
            assert( сomponent != 0 );
        }
        virtual void foo1() { сomponent->foo1(); }
        virtual void foo2() { component->foo2(); }
    private:
        I_A* const component;
    }
};

class A : public I_A
{
public:
    virtual void foo1()
    {
        std::cout<<"foo:"<<"A"<<std::endl;
    }
    virtual void foo2()
    {
        std::cout<<"foo2:"<<"A"<<std::endl;
    }
};

class foo2_decorator: public I_A::decorator_base
{
    
public:
    typedef T base_type;

    foo2_decorator(I_A* component):
        I_A::decorator_base( component )
    {
    }

    void foo2()
    {
        std::cout<<"foo2_decorator:"<<"foo2"<<std::endl;
    }
private:
};

class foo1_decorator: public I_A::decorator_base
{
    
public:
    typedef T base_type;

    foo1_decorator(I_A* component):
        I_A::decorator_base( component )
    {
    }

    void foo1()
    {
        std::cout<<"foo1_decorator:"<<"foo1"<<std::endl;
    }
private:
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout<<"-------------------------------"<<std::endl;
    A a;
    I_A* p_A = &a;
    p_A->foo1();
    p_A->foo2();
    
    std::cout<<"-------------------------------"<<std::endl;
    foo1_decorator a1( p_A );
    p_A = &a1;
    p_A->foo1();
    p_A->foo2();

    std::cout<<"-------------------------------"<<std::endl;
    foo2_decorator a2( p_A );
    p_A = &a2;
    p_A->foo1();    
    p_A->foo2();

    return 0;
}
Но это путь нереального геморра с владением объектами!
У тебя, кстати, в оригинальном примере течёт память!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Интересный вопрос о декораторах на С++.
От: Germes Украина  
Дата: 09.11.10 08:24
Оценка: :)
Здравствуйте, Vamp, Вы писали:

V>А что тебя, собственно, удивляет?

V>p_A = new foo2_decorator<A>(*p_A);

V>Теперь у тебя p_A указывает на объект типа foo2_decorator, в нем foo1 не переопределен. Как еще могло бы быть?



А разве таблица виртуальных методов не копируется ? Скорее происходит усечение.

    foo2_decorator(const base_type& val):
        base_type(val)
    {
    }
С уважением Germes!
Re[2]: Шарпист?
От: Germes Украина  
Дата: 09.11.10 08:39
Оценка:
Здравствуйте, Erop, Вы писали:

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


E>То, какая функция позовётся, определяется исключительно наиболее выведенным типом, а не полями объекта. Так что у типов A, foo1_decorator<A>, foo2_decorator<A> определены методы так, как они определены, вне связи с тем, каой там был аргумент конструктора!


Скорее виртуальная таблица не изменяется при копировании.

Кстати я не спрашивал, как это можно сделать(достаточно было завести базовый декоратор).

class I_A_decorator : public A
{
    I_A* owner_;
public:
    I_A_decorator(I_A* p_owner):
      owner_(p_owner)
    {
    }

    virtual void foo1()
    {
        owner_->foo1();
    }
    virtual void foo2()
    {
        owner_->foo2();
    }
};






E>У тебя, кстати, в оригинальном примере течёт память!

Я в курсе .
С уважением Germes!
Re[3]: Интересный вопрос о декораторах на С++.
От: Erop Россия  
Дата: 09.11.10 08:57
Оценка: :)
Здравствуйте, Germes, Вы писали:


G>А разве таблица виртуальных методов не копируется ? Скорее происходит усечение.


А как бы она могла копироваться?
А *вдруг* той реализации, на которую скопируется указатель, будут нужны какие-то поля в объекте?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Шарпист?
От: Erop Россия  
Дата: 09.11.10 08:58
Оценка: :)
Здравствуйте, Germes, Вы писали:

G>Скорее виртуальная таблица не изменяется при копировании.

Не очень понимаю, что значит "не изменяется", если речь идёт о создании объекта.
Но такое поведение, которого хотел ты, невозможно.

E>>У тебя, кстати, в оригинальном примере течёт память!

G>Я в курсе .
Ну и зачем тогда? Можно же автоматические переменные сдалть было!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Сам Шарпист! :)))
От: Germes Украина  
Дата: 09.11.10 09:41
Оценка:
Здравствуйте, Erop, Вы писали:

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


G>>Скорее виртуальная таблица не изменяется при копировании.

E>Не очень понимаю, что значит "не изменяется", если речь идёт о создании объекта.

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

E>Но такое поведение, которого хотел ты, невозможно.

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

E>>>У тебя, кстати, в оригинальном примере течёт память!

G>>Я в курсе .
E>Ну и зачем тогда? Можно же автоматические переменные сдалть было!

какие автоматические переменные ???? это пример демонстрирующий конкретную проблему. Не более того.

Erop,
большая просьба к вам ,
не стоит уводить дискуссию в сторону всякими ненужными предложениями , как это можно реализовать ,поиском утечек и т. д.
Я все это знаю и без вас.
С уважением Germes!
Re[5]: Сам Шарпист! :)))
От: Erop Россия  
Дата: 09.11.10 12:56
Оценка:
Здравствуйте, Germes, Вы писали:

E>>Но такое поведение, которого хотел ты, невозможно.

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

Либо они совсем не подумали, либо ты их недопонял. Если они не совсем лохи, то вероятнее второе. Иногда причудливую творческую мысль С++-программиста довольно трудно понять, однако.

Почему нельзя копировать таблицы виртуальных функций? Вот пример:
struct A {
    virtual ~A() {}

    virtual int foo() = 0;
};

struct B : A {
    int Field;
    int foo() { return Field++; }
};

struct Decorator : A {
    Decorator( A* a ) : A( *a ) {}
};

int bar()
{
    B b;
    Decorator d( &b );
    return d.foo(); // Если бы было так, как ты думаешь хотели те люди, 
               // то какому полю какого класса должно было быть сделано ++?
}



G>Erop,
G>большая просьба к вам ,
G>не стоит уводить дискуссию в сторону всякими ненужными предложениями , как это можно реализовать ,поиском утечек и т. д.
G>Я все это знаю и без вас.
Ну так и пиши примеры, в которых есть только ОДНА проблема. ИМЕННО та, про которую ты хочешьл спросить.
А то уровень человека, которому нужна помощь не ясен из вопроса, а среди кучи ошибок трудно понять, что именно не устраивает...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Сам Шарпист! :)))
От: jazzer Россия Skype: enerjazzer
Дата: 09.11.10 13:01
Оценка: +1
Здравствуйте, Germes, Вы писали:

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


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


G>>>Скорее виртуальная таблица не изменяется при копировании.

E>>Не очень понимаю, что значит "не изменяется", если речь идёт о создании объекта.

G>скорее всего ожидалось что при создании объекта можно динамически изменить виртуальную таблицу путем подмены инстанса базового класа.


"Виртуальная таблица" в С++ — это сущность уровня класса, а не уровня объекта (в Стандарте это формулируется несколько иначе, но тебе это не нужно, а смысл тот же).
Т.е. она одна на все объекты данного класса (и чаще всего реализуется в виде указателя на эту таблицу, которая одна на всех. Так что даже если ты пролезешь в нее при помощи грязных хаков и что-нть там поменяешь — ты поменяешь поведение всех объектов этого класса).
Если ты хочешь иметь виртуальную таблицу на уровне объекта — тебе придется реализовать ее руками (не ахти как сложно, в принципе).
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Шарпист?
От: andrey_nado  
Дата: 09.11.10 21:46
Оценка:
Здравствуйте, Erop, Вы писали:

E>Ну и вообще, обычно когда хочется смешать шаблоны и виртуальные методы, это обычно говорит, об ошибке дизайна.


Почему? Неужели никогда не приходилось создавать иерархию классов, параметризованных каким-нибудь типом?
Re[3]: Шарпист?
От: Erop Россия  
Дата: 10.11.10 00:25
Оценка:
Здравствуйте, andrey_nado, Вы писали:

_>Почему?

Ну по многим причинам. Кроме того, смешать можно по разному

_>Неужели никогда не приходилось создавать иерархию классов, параметризованных каким-нибудь типом?


Ну, в целом старался избегать. Ясно, что у какой-то системы типов может быть два независимых аспекта. И один может быть сделан через виртуальные методы, а другой через шаблоны. Но под "смешать" я имел в виду немного другое.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.