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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Traits, не для слабых умов =) 
:(
    Опции темы
AtroX
Дата 18.8.2005, 11:53 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Есть иерархия с базовым классом entity, у которого есть некоторые виртуальные функции, типа ProcessMsg(int msg,..), ProcessInit();

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

Предполагается создание иерархии trait'ов, которым будут перенаправляться вызовы функций.

Должны выполняться требования:
1) trait должен уметь делать почти все, что и наследник entity
2) trait не должен обрабатывать функции, если это не требутеся (*)
3) Простой процесс инициализации trait (регистрации пожеланий по обработке функций entity и т.п.)
4) Простой процесс деспетчеризации вызовов

Можно сделать удобные define'ы или использовать механизм шаблонов.

(*) А то можно создать иерархию trait с теми же виртуальными функциями, что и у entity и в entity в каждой виртуальной функции пробегаться по массиву trait'ов и вызывать соответствующие функции - это НЕ катит =)

ОЧЕНЬ важно быстродействие, т.к. используется realtime!

Некоторые виртуальные функции entity вызываются десятки раз в секунду.
  Вверх
Chaos A.D.
Дата 18.8.2005, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 172
Регистрация: 16.1.2005
Где: 09 RUS

Репутация: 6
Всего: 7



Назвать себя человеком, хорошо знающим C++, мне не позволит ни скромность, ни знания, но что-то, на мой взгляд, странноват дизайн, предложенный тобой. Наверное я просто не понял, чего ты хочешь добиться, отказавшись от наследования? Тебе нужен механизм диспетчеризации в runtime, или что?
--------------------
Надо смеяться над тем, что тебя мучит, иначе не сохранишь равновесия, иначе мир сведет тебя с ума...Ken Kesey - One Flew Over The Cocoo's Nest
PM MAIL   Вверх
Void
Дата 18.8.2005, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

Репутация: 40
Всего: 173



Тоже не совсем понял, что требуется... Система подписки на события? Может, Boost.Signals пойдет? Насчет быстродействия не знаю... Если это действительно hard-realtime, то вряд ли, но десятки вызовов в секунду выдюжит... в зависимости от тяжести самих ф-ций, конечно.

P.S. Имхо, термин traits употреблен не к месту.


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
bel_nikita
Дата 19.8.2005, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Эксперт
Сообщений: 2304
Регистрация: 12.10.2003
Где: Поезд №21/22 ( ст . Прага )

Репутация: 21
Всего: 47



Ничего не понял smile
AtroX
Цитата
ОЧЕНЬ важно быстродействие, т.к. используется realtime!
Быстродействие уже теряется, т.к. используются виртуальные вызовы.
И причем тут real-time? Real-time - это не всегда есть быстродействие. Real-time - это прежде всего предсказуемость.

З.Ы.: немного оффтопа smile
Система реального времени (RTOS) это информационная система , в которой корректность выходной информация зависит не только от примененных алгоритмов, но и от моментов времени появления информации.
И система реального времени необязательно быстрая, как кто либо мог считать. Не следует удивляться, что RTOS медлительнее, чем обычные ОС. Например, система навигации корабля в начале могла бы показаться не системой реального времени, потому что скорость мала и обычно "достаточно" времени (порядка минут) для принятия решения. Тем не менее, это действительно система реального времени.
Это, я так smile К тому, что не следует, размахиваться словосочитанием real-time, хотя и модное словечко smile

З.Ы.Ы.: не в обиду конечно smile



--------------------
user posted image — регистрация доменов от 150 руб.
PM MAIL WWW ICQ   Вверх
Hroft
Дата 19.8.2005, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: нет
Всего: 3



Я чего-то не понял, или же после замены наследования на делегирование разные экземпляры entity будут по-разному себя вести, и уже не будет никакого наследования вообще?
Зачем нужна ИЕРАРХИЯ свойств? Их должен быть НАБОР. В чем проблема-то? Ну создавай сущность, задавай ей свойства, где тут виртуальные вызовы? Если только апгрейды всякие делать, но оно тем же самым агрегированием решается...
Не пойму, про что вообще топик...
Не дорос еще, наверно, тоже...
PM MAIL ICQ   Вверх
AtroX
Дата 19.8.2005, 13:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(bel_nikita @ 19.8.2005, 00:50)
что не следует, размахиваться словосочитанием real-time, хотя и модное словечко

Курс ОС я прошел в полном объеме, так что я в этом разбираюсь ;)
real-time пишу, поскольку основная масса людей это понимает, как то, что от приложения требуется максимальная производительность и реактивность.

Цитата(Void @ 18.8.2005, 22:20)
Имхо, термин traits употреблен не к месту.

Traits назвал потому, что они позволяют Entity приобретать новые свойства.

Цитата(Hroft @ 19.8.2005, 12:17)
Ну создавай сущность, задавай ей свойства

И как это делать в runtime?

Цитата(Chaos @ 18.8.2005, 13:11)
Тебе нужен механизм диспетчеризации в runtime, или что?

Именно!

Нужно иметь простой способ (минимум кода), чтобы сделать перенаправление вызовов функций Entity в функции Trait (коих может быть несколько)

В общем то меня вчера посетило вдохновение и я написал, что-то подходящее, если интересно могу опубликовать.
Но все равное есть надежда на простое и элегантное решение, типа применить некую комбинацию паттернов и т.п.
PM MAIL   Вверх
Hroft
Дата 19.8.2005, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: нет
Всего: 3



Цитата(AtroX @ 19.8.2005, 13:24)
Цитата (Hroft @ 19.8.2005, 12:17)
Ну создавай сущность, задавай ей свойства

И как это делать в runtime?

ПОДМЕНОЙ УКАЗАТЕЛЕЙ НА СВОЙСТВА! Именно таким образом агрегирование и может заменить наследование. И только таким (вроде).
PM MAIL ICQ   Вверх
AtroX
Дата 19.8.2005, 13:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(Hroft @ 19.8.2005, 12:17)
Ну создавай сущность, задавай ей свойства, где тут виртуальные вызовы?


Цитата(Hroft @ 19.8.2005, 13:32)
ПОДМЕНОЙ УКАЗАТЕЛЕЙ НА СВОЙСТВА!


Надо было мне полнее процитировать первый раз, а то неувязочка получается. Меня собственно и заинтерисовало, как задавать свойства без механизма виртуальных вызовов. smile
PM MAIL   Вверх
Chaos A.D.
Дата 22.8.2005, 08:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 172
Регистрация: 16.1.2005
Где: 09 RUS

Репутация: 6
Всего: 7



AtroX, было бы интересно посмотреть, как ты решил проблему.

Это сообщение отредактировал(а) Chaos A.D. - 22.8.2005, 08:09
--------------------
Надо смеяться над тем, что тебя мучит, иначе не сохранишь равновесия, иначе мир сведет тебя с ума...Ken Kesey - One Flew Over The Cocoo's Nest
PM MAIL   Вверх
Chaos A.D.
Дата 22.8.2005, 17:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 172
Регистрация: 16.1.2005
Где: 09 RUS

Репутация: 6
Всего: 7



Вообще не совсем понял задачу, но может тебе поможет паттерн Visitor?
--------------------
Надо смеяться над тем, что тебя мучит, иначе не сохранишь равновесия, иначе мир сведет тебя с ума...Ken Kesey - One Flew Over The Cocoo's Nest
PM MAIL   Вверх
AtroX
Дата 22.8.2005, 18:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(Chaos @ 22.8.2005, 08:09)
AtroX, было бы интересно посмотреть, как ты решил проблему.


Так оно применяется (что вполне меня устраивает):
main.cpp
Код

#include "entity.h"
#include "trait.h"

class SomeEntity1 : public BaseEntity {
public:
   virtual void f1(void) {
      Dispatch(f1);
      return ;
   }

   virtual int  f2(float p1) {
      Dispatch(f2, p1);
      return 0;
   }
};

class SomeEntity2 : public SomeEntity1 {
public:
   void f3(int p1) {
      Dispatch(f3, p1);
      return ;
   }
};

class SomeTrait1 : public BaseTrait {
public:
   virtual void f1(void) {
      return ;
   }

   virtual int  f2(float p1) {
      return 0;
   }

   virtual void AttachTo(BaseEntity *pEntity) {
      BaseTrait::AttachTo(pEntity);

      pEntity->Attach(SomeEntity1::f1, makeTraitFn(this, f1));
      pEntity->Attach(SomeEntity1::f2, makeTraitFn(this, f2));
   }

};

class SomeTrait2 : public SomeTrait1 {
public:
   virtual void f1() {
      return SomeTrait1::f1();
   }

   virtual void f3(int p1) {
      return ;
   }

   virtual void AttachTo(BaseEntity *pEntity) {
      SomeTrait1::AttachTo(pEntity);

      pEntity->Attach(SomeEntity2::f3, makeTraitFn(this, f3));
   }
};

void main ()
{
   SomeEntity2 e;
   BaseTrait *pTrait = 0;
   
   pTrait = new SomeTrait1;
   pTrait->AttachTo(&e);

   pTrait = new SomeTrait2;
   pTrait->AttachTo(&e);

   e.f1();   //SomeTrait1::f1, SomeTrait2::f1
   e.f2(2.f);//SomeTrait1::f2, SomeTrait1::f2
   e.f3(2);  //SomeTrait2::f3
}


Собственно то, что позволило так кратенько все записывать, хотя я думаю, что все это нафиг переделаю
MemberFn.h
Код

#pragma once
//
// functors for Member function
template <typename T> class BaseMemFn {
public:
   typedef T CLASS_T;

   BaseMemFn(CLASS_T *pC) : class_ptr(pC) { return ; }
   CLASS_T* GetClass(void) const          { return class_ptr; }

private:
   CLASS_T* class_ptr;// here must be smart_ptr with ref counting
};

//
// Functor with 1 param
template <typename T, typename R, typename P1 = void> class MemFn : public BaseMemFn<T> {
public:
   typedef R (T::*FN_T)(P1);
   FN_T fn;

   MemFn(T *pC, FN_T _fn) : BaseMemFn<T>(pC), fn(_fn) {}

   R operator()(P1 p1) {
      return (GetClass()->*fn)(p1);
   }
};

template <typename T, typename C, typename R, typename P1> MemFn<T,R,P1> makeFunctor(T* pClass, R (C::*fn)(P1))
{
   return MemFn<T,R,P1>(pClass, static_cast<MemFn<T,R,P1>::FN_T>(fn));
}

//
// Functor with 0 params
template <typename T, typename R> class MemFn<T,R, void> : public BaseMemFn<T> {
public:
   typedef R (T::*FN_T)();
   FN_T fn;

   MemFn(T *pC, FN_T _fn) : BaseMemFn<T>(pC), fn(_fn) {}

   R operator()() {
      return (GetClass()->*fn)();
   }
};

template <typename T, typename C, typename R> MemFn<T,R> makeFunctor(T* pClass, R (C::*fn)())
{
   return MemFn<T,R>(pClass, static_cast<MemFn<T,R>::FN_T>(fn));
}


entity.h
Код

#pragma once

#include <map>
#include <vector>
#include "member_fn.h"
//
// Dispatching
//
template <typename T> void *MakeVoidPtr(T t) {
   return *(void**)(&t);
}

class BaseTrait;
//
// BaseEntity
//
class BaseEntity {
public:
   typedef BaseEntity THIS_T;
   typedef BaseTrait  TRAIT_T;

   // pure virtual destructor
   virtual ~BaseEntity() = 0 { return ; }

   // dispatch call to functors, T - for using in derived classes
   template <typename T, typename R>              bool Dispatch(R (T::*fn)());
   template <typename T, typename R, typename P1> bool Dispatch(R (T::*fn)(P1), P1);

   // it's convenient for Entity and Trait fn's signatures check for compatibility, T - for using in derived classes
   template <typename T, typename R>              void Attach  (R (T::*fn)(),   MemFn<TRAIT_T,R>*    functor);
   template <typename T, typename R, typename P1> void Attach  (R (T::*fn)(P1), MemFn<TRAIT_T,R,P1>* functor);

private:
   typedef std::vector<BaseMemFn<TRAIT_T>*> FunctorList;
   typedef std::map<void*, FunctorList>     DispatchMap;

   DispatchMap map;

   void _Attach (void *fn, BaseMemFn<TRAIT_T>* functor) {
      map[fn].push_back(functor);
   }
};

//
// Dispatching
// Dispatch with 0 params
template <typename T, typename R> 
bool BaseEntity::Dispatch(R (T::*fn)())
{
   static_cast<THIS_T*>((T*)0);
   DispatchMap::const_iterator iter = map.find(MakeVoidPtr(fn));
   if (iter == map.end()) return false;
   const FunctorList& fnList = iter->second;

   for (unsigned i = 0; i < fnList.size(); i++) {
      //fnList[i] points to MemFn<TRAIT_T,R> it is guaranted by Attach func
      (*static_cast<MemFn<TRAIT_T,R>*>(fnList[i]))();
   }

   return true;
}

// Dispatch with 1 param
template <typename T, typename R, typename P1> 
bool BaseEntity::Dispatch(R (T::*fn)(P1), P1 p1)
{
   static_cast<THIS_T*>((T*)0);
   DispatchMap::const_iterator iter = map.find(MakeVoidPtr(fn));
   if (iter == map.end()) return false;
   const FunctorList& fnList = iter->second;

   for (unsigned i = 0; i < fnList.size(); i++) {
      //fnList[i] points to MemFn<TRAIT_T,R,P1> it is guaranted by Attach func
      (*static_cast<MemFn<TRAIT_T,R,P1>*>(fnList[i]))(p1);
   }

   return true;
}

//
// Attaching
// Attach with 0 params
template <typename T, typename R> 
void BaseEntity::Attach(R (T::*fn)(), MemFn<TRAIT_T,R>* functor) 
{
   static_cast<THIS_T*>((T*)0); 
   _Attach(MakeVoidPtr(fn), functor); 
}

// Attach with 1 param
template <typename T, typename R, typename P1> 
void BaseEntity::Attach (R (T::*fn)(P1), MemFn<TRAIT_T,R,P1>* functor) 

   static_cast<THIS_T*>((T*)0); 
   _Attach(MakeVoidPtr(fn), functor); 
}



trait.h
Код

#pragma once
class BaseEntity;

class BaseTrait {
public:
   ~BaseTrait()                                    { return; }
   virtual void AttachTo(BaseEntity *pEntity)  = 0 { pOwner = pEntity; }
   BaseEntity*  GetOwner(void) const               { return pOwner; }

private:
   BaseEntity *pOwner;
};

// MemFn<BaseTrait> functor with 1 param
template <typename C, typename R, typename P1> MemFn<BaseTrait,R,P1>* makeTraitFn(BaseTrait* pClass, R (C::*fn)(P1))
{
   return new MemFn<BaseTrait,R,P1>(makeFunctor(pClass, fn));
}

// MemFn<BaseTrait> functor with 0 params
template <typename C, typename R> MemFn<BaseTrait,R>* makeTraitFn(BaseTrait* pClass, R (C::*fn)())
{
   return new MemFn<BaseTrait,R>(makeFunctor(pClass, fn));
}


В принципе, можно обойтись без динамического выделения памяти в makeTraitFn.
Это была первая версия smile . Думаю, можно заюзать что-нибудь из boost'а, но я пока только начал его изучать. Хотя уже впечатлился набором полезностей, которые часто приходилось самому реализовывать.

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


Новичок



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

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



Цитата(AtroX @ 22.8.2005, 18:31)
В принципе, можно обойтись без динамического выделения памяти в makeTraitFn.

Для этого придется решить задачу
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
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.0902 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


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

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