хочу странного: сменить класс объекта в runtime
От: c-smile Канада http://terrainformatica.com
Дата: 31.08.07 16:40
Оценка:
Есть два класса-потомка (A и B) от общего базового абстракта P.

class P
{
   int data;
   virtual foo() = 0;
}

class A: public P
{
   // no class specific data, only methods
   virtual foo() { ++data; }
}

class B: public P
{
   // no class specific data, only methods
   virtual foo() { --data; }
}


Есть некий конкретный instance созданный как A.

P* p = new A;


Существует ли способ сменить класс объекта в p?
Я понимаю что стандартными способами — нет.
Но в принципе это задача смены одного указателя на vtbl у объекта.
Как бы это сделать путем "наименьшего хака"?

Вот такой вот вопрос.
Re: хочу странного: сменить класс объекта в runtime
От: korzh.pavel Россия  
Дата: 31.08.07 16:50
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Есть два класса-потомка (A и B) от общего базового абстракта P.


CS>
CS>class P
CS>{
CS>   int data;
CS>   virtual foo() = 0;
CS>}

CS>class A: public P
CS>{
CS>   // no class specific data, only methods
CS>   virtual foo() { ++data; }
CS>}

CS>class B: public P
CS>{
CS>   // no class specific data, only methods
CS>   virtual foo() { --data; }
CS>}
CS>


CS>Есть некий конкретный instance созданный как A.


CS>
CS>P* p = new A;
CS>


CS>Существует ли способ сменить класс объекта в p?

CS>Я понимаю что стандартными способами — нет.
CS>Но в принципе это задача смены одного указателя на vtbl у объекта.
CS>Как бы это сделать путем "наименьшего хака"?

CS>Вот такой вот вопрос.


P* p = new B;




или я чего то не понял?
Re: хочу странного: сменить класс объекта в runtime
От: Awaken Украина  
Дата: 31.08.07 16:56
Оценка: 1 (1) +2
CS>Существует ли способ сменить класс объекта в p?
CS>Я понимаю что стандартными способами — нет.
CS>Но в принципе это задача смены одного указателя на vtbl у объекта.
CS>Как бы это сделать путем "наименьшего хака"?

pimpl, handle/body, делегация?
Re[2]: хочу странного: сменить класс объекта в runtime
От: Centaur Россия  
Дата: 31.08.07 17:07
Оценка:
Здравствуйте, Awaken, Вы писали:

CS>>Существует ли способ сменить класс объекта в p?

CS>>Я понимаю что стандартными способами — нет.
CS>>Но в принципе это задача смены одного указателя на vtbl у объекта.
CS>>Как бы это сделать путем "наименьшего хака"?

A>pimpl, handle/body, делегация?


+1. И всё это, взятое вместе, называется паттерном State.
Re[2]: хочу странного: сменить класс объекта в runtime
От: c-smile Канада http://terrainformatica.com
Дата: 31.08.07 18:13
Оценка:
Здравствуйте, Awaken, Вы писали:

CS>>Существует ли способ сменить класс объекта в p?

CS>>Я понимаю что стандартными способами — нет.
CS>>Но в принципе это задача смены одного указателя на vtbl у объекта.
CS>>Как бы это сделать путем "наименьшего хака"?

A>pimpl, handle/body, делегация?


Эти слова я знаю. Плюсы и минусы тоже знаю. Все эти подходы определяют новые сущности.

Мысли вслух:

Хочется простой вещи типа:

P* p = new A;
new(p) B;


Надо по-эксперементировать ...
Re[3]: хочу странного: сменить класс объекта в runtime
От: _nn_ www.nemerleweb.com
Дата: 31.08.07 18:34
Оценка:
Здравствуйте, c-smile, Вы писали:

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


CS>>>Существует ли способ сменить класс объекта в p?

CS>>>Я понимаю что стандартными способами — нет.
CS>>>Но в принципе это задача смены одного указателя на vtbl у объекта.
CS>>>Как бы это сделать путем "наименьшего хака"?

A>>pimpl, handle/body, делегация?


CS>Эти слова я знаю. Плюсы и минусы тоже знаю. Все эти подходы определяют новые сущности.


CS>Мысли вслух:


CS>Хочется простой вещи типа:


CS>
CS>P* p = new A;
CS>new(p) B;
CS>


CS>Надо по-эксперементировать ...


Может проще будет создать 2 объекта сразу ?
P* f(bool need_a)
{
 static A a;
 static B b;

 return need_a ? &a : &b;
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: хочу странного: сменить класс объекта в runtime
От: Went  
Дата: 31.08.07 18:34
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Хочется простой вещи типа:


CS>
CS>P* p = new A;
CS>new(p) B;
CS>


CS>Надо по-эксперементировать ...


А если что-то вроде:
P* p = new A;
//Do something
p = new B(*p);


Хотя, в этом случае, однозначно рулит компонентность, добавить компоненту, отвечающую за это действие.
Re: хочу странного: сменить класс объекта в runtime
От: c-smile Канада http://terrainformatica.com
Дата: 31.08.07 18:59
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Существует ли способ сменить класс объекта в p?

CS>Я понимаю что стандартными способами — нет.
CS>Но в принципе это задача смены одного указателя на vtbl у объекта.
CS>Как бы это сделать путем "наименьшего хака"?
CS>Вот такой вот вопрос.

Вот эта вот кострукция компилируется на ура и делает то что надо:


#include "new.h"

struct P
{
   int data;
   P() {}
   virtual ~P() {}
   virtual foo() = 0;
};

template <typename T>
  inline P* ctor(int d) { P* t = new T; t->data = d; return t; }
template <typename T>
  inline void turn_to(P* p) { ::new(p) T; }

struct A: public P
{
   // no class specific data, only methods
   virtual foo() { ++data; }
};

struct B: public P
{
   // no class specific data, only methods
   virtual foo() { --data; }
};

int main(int argc, char* argv[])
{
  P *p = ctor<A>(0);
  p->data = 0;
  p->foo();
    printf("step 1, p.data = %d\n", p->data);
  turn_to<B>(p);
  p->foo();
  printf("step 2, p.data = %d\n", p->data);
    return 0;
}


Проверяю дальше.
Re[2]: хочу странного: сменить класс объекта в runtime
От: c-smile Канада http://terrainformatica.com
Дата: 31.08.07 20:12
Оценка: :))
Здравствуйте, korzh.pavel, Вы писали:

KP>или я чего то не понял?


Угу

"Ну как ты мог обо мне так плохо подумать?"
Re[2]: хочу странного: сменить класс объекта в runtime
От: Константин Л. Франция  
Дата: 31.08.07 20:13
Оценка:
Здравствуйте, c-smile, Вы писали:

[]

не красиво это как-то,

может лучше так?




class Implementation
{
     virtual void f() = 0;
}

struct P
{
   int data;
   P() {}

   void SetImpl( Implementation* impl );

   virtual ~P() {}
   virtual foo() = 0;
};
Re: Два пути в ад uB :)
От: Erop Россия  
Дата: 31.08.07 21:17
Оценка: 14 (1)
Здравствуйте, c-smile, Вы писали:

CS>Есть два класса-потомка (A и B) от общего базового абстракта P.

CS>Как бы это сделать путем "наименьшего хака"?

Тема раз:
template<class T> P* CreateHackedObject()
{
    void * buffer = new char[sizeof T];
    return new( buffer ) T;
}

void DeleteHackedObject( P* p )
{
    if( p == 0 )
        return;
    p->~P();
    delete [] static_cast<char*>( (void*)p );
}

template<class TFrom, class TTo> void SwitchTo( P* p )
{
    static_assert( sizeof( TFrom ) >= sizeof( TTo ) );
    assert( dynamic_cast<TFrom*>( p ) != 0 );
    p->~P();
    new( p ) TTo;
    assert( dynamic_cast<TTo*>( p ) != 0 );
}


Вроде даже без UB всюду...

Тема два (хмурое хаккерство, но...)
template<class TFrom, class TTo> void UnsafeSwitchTo( P* p )
{
    static_assert( sizeof( TFrom ) == sizeof( TTo ) );
    assert( dynamic_cast<TFrom*>( p ) != 0 );
    {
        TTo tmp;
        memcpy( p, &tmp, sizeof( tmp ) );
    }
    assert( dynamic_cast<TTo*>( p ) != 0 );
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Два пути в ад uB :)
От: c-smile Канада http://terrainformatica.com
Дата: 31.08.07 22:06
Оценка:
Здравствуйте, Erop, Вы писали:

E>
template<class TFrom, class TTo> void SwitchTo( P* p )
E>{
E>    static_assert( sizeof( TFrom ) >= sizeof( TTo ) );
E>    assert( dynamic_cast<TFrom*>( p ) != 0 );
    p->~P();
E>    new( p ) TTo;
E>    assert( dynamic_cast<TTo*>( p ) != 0 );
E>}
E>


Мне p->~P(); как раз не нужен.

Мне нужно переключить behavior класса в зависимости от некоего условия.
Операции конструирования и копирования объектов достаточно дорогие.
Поэтому все что я могу себе позволить это переключить vtbl

E>Вроде даже без UB всюду...


Не вижу я там UB. TFrom и TTo ничего не добавляют в instance.
Отличие этих классов сугубо в vtbl.
Re[3]: хочу странного: сменить класс объекта в runtime
От: c-smile Канада http://terrainformatica.com
Дата: 31.08.07 22:13
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>может лучше так?


КЛ>

КЛ>class Implementation
КЛ>{
КЛ>     virtual void f() = 0;
КЛ>}

КЛ>struct P
КЛ>{
КЛ>   int data;
КЛ>   P() {}

КЛ>   void SetImpl( Implementation* impl );

КЛ>   virtual ~P() {}
КЛ>   virtual foo() = 0;
КЛ>};


КЛ>


Я не понял если честно.

Что-бы это имело смысл то это должно выглядеть так:

class Implementation
{
   virtual void f(P* p) {...}
}

struct P
{
   Implementation* pimpl;
   int data;

   P() {}
   void SetImpl( Implementation* impl ) { pimpl = impl; }

   ~P() {}
   void foo() { pimpl->foo(this); };
};


Это собственно и есть то что строит compiler унутре.
Т.е. зачем мне изобретать велосипед по новой?
Re[4]: хочу странного: сменить класс объекта в runtime
От: c-smile Канада http://terrainformatica.com
Дата: 01.09.07 02:23
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Может проще будет создать 2 объекта сразу ?

__>
__>P* f(bool need_a)
__>{
__> static A a;
__> static B b;

__> return need_a ? &a : &b;
__>}
__>


"Не канает".

Задача примерно такова: есть DOM tree

namespace html
{
  struct element
  {
    ... data ...
    void do_layout() = 0;
  };

  struct paragraph : public element
  {
    void do_layout()  { layout as a text container };
  };

  struct div : public element
  {
    void do_layout()  { layout as a block container };
  };
}


Каждый элемент в зависимости от CSS атрибута:
display-model: block-inside | inline-inside | table

должен переключать способ do_layout и чертову силу других методов.

Причем display-model может переключаться динамически (во всяком случае это не запрещено)

Вот такие вот пироги. Два (5 на самом деле) объекта создавать само собой я даже и не знаю как.
Re[4]: хочу странного: сменить класс объекта в runtime
От: Аноним  
Дата: 01.09.07 08:30
Оценка: +1
Здравствуйте, c-smile, Вы писали:

CS>Это собственно и есть то что строит compiler унутре.

CS>Т.е. зачем мне изобретать велосипед по новой?

Потому что ты не должен даже догадываться о существовании этих велосипедов.
Дело то внутреннее...

Нормальные решения тебе уже в общем-то подсказали.
Непонянтно почему ты их игнорируешь...
Re[3]: Два пути в ад uB :)
От: Константин Л. Франция  
Дата: 01.09.07 10:57
Оценка:
Здравствуйте, c-smile, Вы писали:

[]

CS>Мне p->~P(); как раз не нужен.


CS>Мне нужно переключить behavior класса в зависимости от некоего условия.

CS>Операции конструирования и копирования объектов достаточно дорогие.
CS>Поэтому все что я могу себе позволить это переключить vtbl

Только зачем это делать, рискуя нарваться на неприятности с placement new?

здесь
Автор: Константин Л.
Дата: 01.09.07
я показал как примерно это лучше сделать (с твоими дополнениями конечно)

[]
Re: хочу странного: сменить класс объекта в runtime
От: Programador  
Дата: 01.09.07 12:19
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Есть два класса-потомка (A и B) от общего базового абстракта P.

ну первое это vtab вручную — поместить в класс указатели на методы.

Просто переписать vtab по адресу (viud *(&))(*this)

placement new — воспользоватся раздельной компиляцией и описать одноименный пустой класс без всяких data только обьявления виртуальных методов в томже порядке. И public на те классы где есть виртуальные методы. Тогда по идее структура vtabl сохранится, а побочного ффекта от конструкторов-деструкторов не будет

Описать сначала невиртуальные методы, потом перекрыть (продублировать) ихже виртуальными, тогда можно вернутся к той базе где виртуальных нет
Re[3]: Два пути в ад uB :)
От: korzh.pavel Россия  
Дата: 01.09.07 16:59
Оценка: 30 (1)
Здравствуйте, c-smile, Вы писали:

CS>Мне нужно переключить behavior класса в зависимости от некоего условия.

CS>Операции конструирования и копирования объектов достаточно дорогие.
CS>Поэтому все что я могу себе позволить это переключить vtbl

http://rsdn.ru/forum/message/626591.aspx
Автор: alnsn
Дата: 02.05.04


?
Re[5]: хочу странного: сменить класс объекта в runtime
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.09.07 17:16
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>должен переключать способ do_layout и чертову силу других методов.


CS>Причем display-model может переключаться динамически (во всяком случае это не запрещено)


Читать "Паттерны проектирования". Решение твоей проблемы — паттерн State, вероятнее всего тебе также понадобятся Factory method и Composite.

В vtbl лезть не стоит.
Re[6]: хочу странного: сменить класс объекта в runtime
От: c-smile Канада http://terrainformatica.com
Дата: 01.09.07 17:30
Оценка:
Здравствуйте, gandjustas, Вы писали:

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


CS>>должен переключать способ do_layout и чертову силу других методов.


CS>>Причем display-model может переключаться динамически (во всяком случае это не запрещено)


G>Читать "Паттерны проектирования". Решение твоей проблемы — паттерн State, вероятнее всего тебе также понадобятся Factory method и Composite.


Спасибо.

G>В vtbl лезть не стоит.


Я не лезу.

Вот пример того как это можно сделать:
http://www.rsdn.ru/forum/message/2641817.1.aspx
Автор: c-smile
Дата: 31.08.07

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