2012-08-11 4 views
1

У меня есть очень простое определение класса следующим образом:Пытаясь избежать многократного вызова функции

#include "../bshttp/controllers.h" 
#include <iostream> 
#include <string> 

class DerivedController : public BS_Controllers 
{ 
    public: 
    DerivedController():BS_Controllers(this) 
    { 
     m_urlRules["print"] = REG_NAME &DerivedController::print; 
     //regController(REG_NAME &DerivedController::print,"print"); 
     regController(REG_NAME &DerivedController::printView,"printView"); 
    } 
    void * print() 
    { 
     return NULL; 
    } 
    void * printView() 
    { 
     cout<<"Print view!"<<endl; 
     return NULL; 
    } 
}; 

где либо

m_urlRules["print"] = REG_NAME &DerivedController::print; 

или

regController(REG_NAME &DerivedController::printView,"printView"); 

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

Все хорошо работает и работает, но когда структура класса становится больше, программисту придется повторить эту функцию для каждой отдельной функции-члена. Есть ли в любом случае использовать препроцессор или любую библиотеку предварительной обработки, такую ​​как волна boost-wave, чтобы программисту не приходилось выполнять эти повторные вызовы?

EDIT: Извините за недоразумение, я явно недостаточно описывал проблему. Я привязываю строки к указателю функции-члена;

m_urlRules является станд :: карта с строкой в ​​качестве ключа, и указатель на функцию члена в качестве значения regController в основном функция сеттер для m_urlRules, поэтому оба утверждения фактически делает то же самое, что отображает строку в функции члена ,

REG_NAME - это макрос, заменяющий очень уродливый тип.

, что я пытаюсь сделать то, что, если класс, где иметь следующую структуру,

class DerivedController : public BS_Controllers 
{ 
    public: 
    DerivedController():BS_Controllers(this); 
    void * print(); 
    void * print2(); 
    void * print3(); 
    void * print4(); 
}; 

я не должен выполнить следующие действия в конструкторе:

m_urlRules["print"] = REG_NAME &DerivedController::print; 
m_urlRules["print1"] = REG_NAME &DerivedController::print1; 
m_urlRules["print2"] = REG_NAME &DerivedController::print2; 
m_urlRules["print3"] = REG_NAME &DerivedController::print3; 
m_urlRules["print4"] = REG_NAME &DerivedController::print4; 
+0

Кажется, вы описываете проблему с воображаемым способом сделать что-то, а не описывать что-то, что есть? –

+0

Где и как определяются 'm_urlRules' и' regController'? Является ли 'REG_NAME' макросом, который делает какой-то листинг? – jxh

+0

'm_urlRules' - это std :: map для строк для указателей функций-членов. 'regController' в основном является сеттером для карты, которая делает то же самое. 'REG_NAME' - макрос типа – leorex

ответ

0

Ну, вы пытаетесь создать информацию типа времени выполнения (RTTI) самостоятельно, поэтому нет макроса препроцессора для этого. В основном потому, что макросы препроцессора расширяются до одного места, а место, где вы объявляете, и место, где вы регистрируете свои функции, различны.

Qt и qmake, что-то вроде этого, он обнаруживает функции, обозначенные сигналами/слотами, и строит объект moc для RTTI. Это самое лучшее, что вы можете получить с помощью C++. Другие языки, такие как java и delphi, имеют больше RTTI, чем C++, и позволяют запрашивать функции во время выполнения.

+0

Да, я пытаюсь сделать базовый RTTI, но все, что мне нужно, это имя функции-члена и указатель функции-члена класса, что я и делаю. – leorex

+0

Ну, Qt-способ - создать отдельный файл для RTTI для каждого класса Q_OBJECT. qmake обрабатывает файл и прослушивает макросы qt, такие как Q_OBJECT, SIGNAL и SLOT, и создает файл. Это лучшее, что вы можете получить, потому что оно полностью автоматическое. Вы можете попробовать то же самое. Ему нужен минимальный парсер, ведьма понимает только базовый класс. Вы даже можете пропустить большинство макросов, но вам нужно что-то вроде Q_OBJECT –

+0

Q_OBJECT - самый разумный способ пойти, просто я стараюсь избегать использования библиотеки Qt по своей собственной причине. – leorex

0

Я нахожусь не совсем уверен, что я полностью понял вашу проблему, но почему бы не использовать встроенную структуру данных, такую ​​как карта, в которой вы можете сопоставить ее с ключом (вашей строкой).

Here some examples

+0

Извините, что недостаточно хорошо описываем проблему. m_urlRules уже является std :: map – leorex

0

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

Я думаю, что вы ищете что-то вроде:

urlRules  ("<function name>"); 
regController("<function name>"); 

Вместо

m_urlRules["<function name>"] = REG_NAME &DerivedController::print; 
regController(REG_NAME &DerivedController::printView,"<function name>"); 

Вы можете определить такие Makros так:

#define  urlRules(x) { m_urlRules[(x)] = REG_NAME &DerivedController::print; } 
#define regController(x) { regController(REG_NAME &DerivedController::printView,(x)); } 

Внимание: я не имею протестировал его, он может не работать, но в моем понимании он должен.

EDIT:

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

См., что функции класса существуют только один раз в памяти, а то, что связано с указателем, - данные урожайности, поэтому все переменные-члены.

Нет простого способа получить всех членов класса по имени, а затем запустить их, извините. По крайней мере, не так, как я знаю.

Но вы должны иметь в виду, что указатели функций не будут изменяться для какого-либо данного объекта. Внешняя функция, которая делает работу более разумной. Вызывается при запуске.

+0

Вы правы, внешние вызовы будут лучше.Но что более важно, я пытаюсь найти автоматический метод для добавления всех этих функций. Угадайте, что мне не повезло .. – leorex

0

Я бы сначала работал над удалением уродливого типа (даже в макросъемке). Это можно сделать, перемещая m_urlRules из BS_Controllers и в промежуточный (или прокси) шаблонный класс. Шаблон используется для разрешения карты на правильный производный тип. (Я не знаю, как вы определили BS_Controllers, поэтому я сделал один.)

class BS_Controllers { 
protected: 
    virtual ~BS_Controllers() {} 
public: 
    virtual void * invokeRule (const std::string &) = 0; 
}; 

template <typename D> 
class BS_Proxy : public BS_Controllers { 
    typedef std::map<std::string, void *(D::*)()> UrlRuleMap; 

    static UrlRuleMap & urlRules() { 
     static UrlRuleMap urlRules_; 
     return urlRules_; 
    } 

    void * invokeRule (const std::string &s) { 
     typename UrlRuleMap::iterator i = urlRules().find(s); 
     if (i == urlRules().end()) return 0; 
     return (dynamic_cast<D *>(this)->*(i->second))(); 
    } 

protected: 
    static void regController (void *(D::*m)(), const std::string &s) { 
     urlRules()[s] = m; 
    } 
}; 

Теперь DerivedController можно инициализировать довольно легко, с помощью вызова метода regController прокси-класса.

#define REG_RULE(D, x) BS_Proxy<D>::regController(&D::x, #x) 

class DerivedController : public BS_Proxy<DerivedController> { 
    struct Populate { 
     Populate() { 
      REG_RULE(DerivedController, print); 
      REG_RULE(DerivedController, printView); 
     } 
    }; 
public: 
    DerivedController() { 
     static Populate populate_; 
    } 
    void * print() { return NULL; } 
    void * printView() { 
     std::cout<<"Print view!"<<std::endl; 
     return NULL; 
    } 
}; 

Вы можете просмотреть demo указанного выше кода.

Если вы хотите, чтобы сделать население полуавтоматический, вы должны определить список методов где-то. Вы можете указать их в файле.

// DerivedController rules 
DERIVED_RULE_INC(print) 
DERIVED_RULE_INC(printView) 
//... 

А затем измените DerivedController класс, чтобы использовать этот файл:

class DerivedController : public BS_Proxy<DerivedController> { 
    struct Populate { 
     Populate() { 
      #define DERIVED_RULE_INC(x) REG_RULE(DerivedController, x); 
      #include "derived_controller_rules.inc" 
      #undef DERIVED_RULE_INC 
     } 
    }; 
public: 
    DerivedController() { 
     static Populate populate_; 
    } 
    #define DERIVED_RULE_INC(x) void * x(); 
    #include "derived_controller_rules.inc" 
    #undef DERIVED_RULE_INC 
}; 

void * DerivedController::print() { return NULL; } 

void * DerivedController::printView() { 
    std::cout<<"Print view!"<<std::endl; 
    return NULL; 
} 

Теперь, если добавить еще одно правило в файл, регистрационный код и объявление метода является автоматическим. Но определение метода должно быть реализовано, или возникает ошибка компоновщика в отношении определения отсутствующего метода.