imho.ws |
![]() |
![]() |
![]() |
# 1 |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
таблица пойнтеров на методы разных классов
Вопрос к гуру С++ :
Имеется в наличии Код:
void C1::m1(int ); void C1::m2(int ); void C2::m3(int ); void C2::m4(int ); нужно сделать такой выкрутас чтобы а) хранить таблицу пойнтеров на методы (заметьте разных классов - кастинг в пойнтер войд не предлагать) б) в зависимисти от инпута вызывать соответсвующий метод по пойнтеру: т.е если инпут 1 - вызывать по пойнтеру на C1::m1(), а если 3 - вызывать C2::m3() Сегодня у меня есть уже класс для вызова методов но только для одного класса, и я вызываюнужный метод по Код:
(m_pBaseClass->*pMethod)(nIntValue) Заранее спасибо. |
![]() |
![]() |
# 2 |
Full Member
Регистрация: 20.01.2004
Адрес: Таллинн
Пол: Male
Сообщения: 623
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Я конечно не гуру С++, но если у тебя куча классов с одинаковыми методами, это похоже на стандартный фабричный шаблон.
http://www.google.ee/search?hl=et&cl...&btnG=Otsi&lr= |
![]() |
![]() |
# 3 |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
похоже на правду. А примерчик накидать можно? как сделать
Код:
C3 executor; executor.run(3, 18); P.S. я не программер, и пример жизненно необходим. Если C1 и C2 наследники С0 - это что-то меняет? Последний раз редактировалось crawler; 30.04.2007 в 15:14. |
![]() |
![]() |
# 4 |
Full Member
Регистрация: 16.10.2002
Адрес: ArchLinux, Internet
Сообщения: 557
![]() ![]() ![]() ![]() |
Предложение: не надо хранить указатели на функции. Храни функторы (functor). Т.к. это нормальные объекты то делаешь наследование и всё ок.
Вот объяснение: http://en.wikipedia.org/wiki/Function_object |
![]() |
![]() |
# 5 | |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Повторю еще раз Я -НЕ ПРОГРАММИСТ. Мне нужно сделать так, чтобы я мог запускать методы разных классов не зная их имени и порядок во время компиляции.
Фраза Цитата:
![]() Код:
class T; class Run { typedef int (T::*Method)(int ); typedef struct { int index public: Run(T* pT) { m_pBaseClass = pT; }; int Call( int nMethIndex, int nParam) { int res; if (nMethIndex == 1) res = (m_pBaseClass->*m_m1)(nParam); if (nMethIndex == 2) res = (m_pBaseClass->*m_m2)(nParam) ; return res; } void Map( Method m1, Method m2) { m_m1 = m1; m_m2 = m2;} private: T* m_pBaseClass; Method m_m1; Method m_m2; }; Последний раз редактировалось crawler; 01.05.2007 в 14:15. |
|
![]() |
![]() |
# 6 |
Full Member
Регистрация: 16.10.2002
Адрес: ArchLinux, Internet
Сообщения: 557
![]() ![]() ![]() ![]() |
примерно так выглядят фанкторы:
Код:
class Functor { public: virtual void Call(Smth & smth) = 0; }; class FunctorA : public Functor { public: virtual void Call(Smth & smth) { smth->RunA(); } }; class FunctorB : public Functor { public: virtual void Call(Smth & smth) { smth->RunB(); } }; надеюсь стало понятнее |
![]() |
![]() |
# 7 |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Код:
class C1; class C2; class FunctorA : public Functor { public: virtual void Call( C1 & smth) { smth->RunA(); } }; class FunctorB : public Functor { public: virtual void Call(C2 & smth) { smth->RunB(); } }; ... Functor fTable[2]; ... fill table here ... fTable[0].Call(); // вызов RunA(); fTable[1].Call();// вызов RunВ(); |
![]() |
![]() |
# 8 |
Full Member
Регистрация: 16.10.2002
Адрес: ArchLinux, Internet
Сообщения: 557
![]() ![]() ![]() ![]() |
к сожалению, прототип Call должен быть одинаков во всех классах. Поэтому может так:
Код:
class C1; class C2; class FunctorA : public Functor { public: virtual void Call( Input & input) { m_c1.Do(input); } C1 & m_c1; }; class FunctorB : public Functor { public: virtual void Call(Input & input) { m_c2.Do(input); } C2 & m_c2; }; |
![]() |
![]() |
# 9 |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
чего-то слишком сложно получается... Я ведь с самого начала хотел избежать выраженного вызова m_c1.Do() Если несколько методов у каждого класса C1, C2, то как я с ними расправлюсь?
... или я чего не понимаю ? пока додумался использовать темплейты, но как сделать для 2 классов одновременно - не понимаю Код:
template <typename BaseClass> class Caller { typedef int (BaseClass::*Method)(int); public: Caller (BaseClass *pInstance) { m_pInstance = pInstance; } void Map ( std::string Name, Method mPtr) { m_Method[Name]= mPtr; } int Call ( std::string Name, int param) { if (m_Method.find(Name)!=m_Method.end()) return (m_pInstance->*(m_Method[Name]))(param); else return 0; } private: std::map<std::string,Method> m_Method; BaseClass *m_pInstance; }; |
![]() |
![]() |
# 10 |
Full Member
Регистрация: 16.10.2002
Адрес: ArchLinux, Internet
Сообщения: 557
![]() ![]() ![]() ![]() |
Я наверное сам ничего не понимаю, запутался. У тебя есть:
class B; class D1 : public B; class D2 : public B; почему бы не определить методы m... виртуальными и держа указатель на B просто вызывать их? |
![]() |
![]() |
# 11 |
Junior Member
Регистрация: 19.04.2002
Адрес: Дом
Пол: Male
Сообщения: 187
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Для начала неплохо было бы понять ради чего конкретно городить огород, вообще? А уж потом решать как это организовывать. Не совсем понятная постановка задачи.
Я так понял что имеется мношество каких-то алгоритмов, которые прменяются к инту в зависимости от контекста, тогда возможно что следует просто завести множество унифицированных классов алгоритмов и сделать для них общий автоматический азпускальшик по контексту?
__________________
Дураки не динозавры - они не вымрут... |
![]() |
![]() |
# 12 | |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Для чего это нужно - я написал простенький интерпретатор, заточенный под мои нужды. У меня есть несколько алгоритмов которые применяются к интерфейс-классу параметров (в примере заменено на int). Алгоритмы запускаются один за другим в какой-то последовательности, заданной в файле конфигурации. Я читаю файл конфигурации и запускаю алгоритмы в том порядке, как в нем указано.
У меня есть несколько уже существующих классов для разных семейств алгоритмов. Пока я работаю с каким-то одним классом -все нормально, тот код что я привел в посте #9 меня полностью устраивает: там есть инстанс (я имею в виду инициализированный об'ект - пользуююсь своим жаргоном) класса, и я запускаю его методы как мне и нужно. Но если мне надо работать с 2 классами одновременно - то мне нужно какое-то образование, чтобы держало инстансы всех нужных мне классов, и вызывало их методы в зависимости от входных данных. Надо учесть что классы алгоритмов уже написаны и их сильно менять не желательно -сегодня я просто добавил "обертку" на существующие методы, чтобы унифицировать интерфейс. Цитата:
как бы я хотел, чтобы это выглядело в коде : Код:
class CAlg1; // has methods m11(), m12(), m13() class CAlg2; // has methods m11(), m12(), m13() // all method have same declaration int mXX( int ) ... CAlg1 a1(1,2,3); // initialize class CAlg2 a2(3,4); // initialize class Caller interp(a1, a2); // initialize Caller class with necessary algoritihms instances // Set mapping from name to method interp.Map("m11", &CAlg1::m11); interp.Map("m12", &CAlg1::m12); interp.Map("m13", &CAlg1::m13); interp.Map("m21", &CAlg2::m21); interp.Map("m22", &CAlg2::m22); ... interp.Call("m11", 0); // call specific algorithm interp.Call("m21", 10); // call specific algorithm while ( /* read method and params from file */ ) interp.Call(method, params); |
|
![]() |
![]() |
# 13 |
Junior Member
Регистрация: 19.04.2002
Адрес: Дом
Пол: Male
Сообщения: 187
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Так и думал что это интерпретатор. :-)
Доберусь домой, попробую накропать маленький приерчик.
__________________
Дураки не динозавры - они не вымрут... Последний раз редактировалось PSyton; 02.05.2007 в 12:56. |
![]() |
![]() |
# 14 |
Full Member
Регистрация: 20.01.2004
Адрес: Таллинн
Пол: Male
Сообщения: 623
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
|
![]() |
![]() |
# 15 |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
EvroStandart, Спасибо, но сюда фабрика не подходит. Фабрика дает выбрать какой именно об'ект инициализировать. В моем случае я должен держать инстансы обеих классов, и вызывать подходящий метод из какого-то одного. Хотя на той же странице я нашел "Chain of Responsibility Design Pattern" - это судя по всему то что мне нужно. Сча буду разбираться.
|
![]() |
![]() |
# 16 |
Junior Member
Регистрация: 19.04.2002
Адрес: Дом
Пол: Male
Сообщения: 187
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Естественно это не скомпилируется сразу - это только первые наметки, еслои так можно сказать. Суть данного метода в том что можно сделать как раз обертку на уже готовый функционал. С помощью шаблонов все это можно расширить таким образом чтобы при наследовании от уже написанного ранее класса алгоритма (не по данной схеме) его конструктор вызывался автоматом, после чего можно получить более красивые вещи, например, для регистрации алгоритмов использовать более хитрые шаблоны, более корректно проверяющие что им подают в качестве параметров шаблона...
Еще раз повторяю что все что приведено ниже это просто наметки и намеки, на то как можно сделать. Код:
class ArgumentsList { private: //... public: ArgumentsList() {} ArgumentsList(const ArgumentsList& other) { *this = other; } ArgumentsList &operator=(const ArgumentsList& other) { if (this != &other) { //Копируем все что надо } return *this; } ~ArgumentsList() {}; }; class Results { public: Results(); //Вся реализация конструкторы копирования и т.п. ~Results(); }; // Базовый клас алгоритма. class BaseAlgoritm { private: std::string m_invokedMethod; protected: void dummyTest(); public: IBaseAlgoritm(const std::string& methodName) : m_invokedMethod(methodName) { } virtual ~IBaseAlgoritm() ( ) virtual const std::string& invikedMethod() const { return m_invokedMethod; } virtual bool canProccess(const std::string& methodName) { return (methodName == m_invokedMethod); } virtual Results proccess(const ArgumentsList& args) = 0; }; class Algoritm : public BaseAlgoritm { public: Algoritm(const std::string& methodName) : BaseAlgoritm(methodName) { dummyTest(); } virtual ~Algoritm() ( ) }; //Предположим что есть класссы A1 и B1 которые что-то там делают... Нам нужно на их основе написать свои алгоритмы... //Делаем наследника от A1 class AA1 : public A1 , public Algoritm { AA1(int a, int b, int c) : A1(a, b, c) , Algoritm("m1") {} virtual ~AA1() {} //Реализуем функцию которая будет выполнять действия... virtual Results proccess(const ArgumentsList& args) { retrun A1::m1(args); } }; //Аналогично для B1 class BB1 : public B1 , public Algoritm { BB1(int a, int b) : B1(a, b) , Algoritm("m2") {} virtual ~BB1() {} //Реализуем функцию которая будет выполнять действия... virtual Results proccess(const ArgumentsList& args) { retrun B1::m2(args); } }; // так далее. Суть в том что каждый наследник класса-примеси Algoritm обязан реализовать proccess, таким образом имеем общий интерфейс для все алгоритмов реализованных подобным образом. // По идее можно не использовать примесь в виде уже реализованного класса, а просто делать наследника от Algoritm и реализовывать его соотв образом. // Интерпретатор примет рпимерно такой вид: class Interpret { private: typedef std::list<BaseAlgoritm *> AList; AList m_algoritms; public: Interpret() {} virtual ~Interpret() { while (m_algoritms.size() > 0) { delete *(m_algoritms.begin()); m_algoritms.erase(m_algoritms.begin()); } } Results invore(const std::string &method, const ArgumentsList& args) { AList::const_iterator i = m_algoritms.begin(); AList::const_iterator ei = m_algoritms.end(); for (; i != ei; ++i) { if ((*i)->canProccess(method)) return (*i)->proccess(args) } return Results(); } bool contains(const std::string &method) { AList::const_iterator i = m_algoritms.begin(); AList::const_iterator ei = m_algoritms.end(); for (; i != ei; ++i) { if ((*i)->canProccess(method)) return true; } return false; } template <class AT> void register(int a, int b, int c) { AT* newalg = new AT(a, b, c); if (!contains(newalg->invikedMethod())) m_algoritms.push_back(newalg); else delete newalg; } template <class AT> void register(int a, int b) { AT* newalg = new AT(a, b); if (!contains(newalg->invikedMethod())) m_algoritms.push_back(newalg); } }; int _tmain(int argc, _TCHAR* argv[]) { Interpret tmp; tmp.register<AA1>(10,5.3); tmp.register<BB1>(5,22); ArgumentsList lst1; ArgumentsList lst2; Results rr = tmp.invore("m1", lst1); Results rr1 = tmp.invore("m2", lst2); }
__________________
Дураки не динозавры - они не вымрут... Последний раз редактировалось PSyton; 02.05.2007 в 17:36. Причина: кое-что поправил. |
![]() |
![]() |
# 17 |
Newbie
Регистрация: 17.06.2002
Сообщения: 30
![]() |
посмотри boost::function
конкретно вот это: http://boost.org/doc/html/function/t...html#id2688553 PS сильно не вникал в суть дискуссии, так что может быть мимо ![]() |
![]() |
![]() |
# 18 |
Full Member
Регистрация: 11.12.2002
Сообщения: 864
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
PSyton, попытался расширить с помощь шаблонов - умудрился вышибить компайлер с ексепшеном
![]() ![]() Flexz, не это то что надо. Я тоже наткнулся на несколько решений - но чтобы их исползовать надо понять как - а весь boost написан так, что мне проще написать самому, чем разобраться как его пользовать. -------------------------------- Сделал. В интерпретаторе хранятся пойнтеры на базисный класс, темплейтом сделал регистрацию с разным количеством входных переменных, и промежуточный класс тоже темплейтный. Вызывается виртуальные метод "Call" базисного класса, и из-за инициации наследников подходящими методами все работает. Таким образом вызов выглядит так: Код:
C1 c1; C2 c2; Interpreter i; i.Register<C1> ( &c1, "m11",&C1::m1, "m12",&C1::m2, NULL ); i.Register<C2> ( &c2, "m21",&C2::m1, "m22",&C2::m2, "m23",&C2::m4, NULL ); i.Call("m23",12); Последний раз редактировалось crawler; 14.05.2007 в 14:23. Причина: Update |
![]() |