crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> Аналог Q_PROPERTY
igor_bogomolov
  опции профиля:
сообщение 30.7.2009, 10:58
Сообщение #1


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


Пытаюсь реализовать аналог Q_PROPERTY.

Раскрывающийся текст
class base {
public:
    typedef bool(*sp)(int);
    typedef int(*gp)();
    typedef std::pair<sp, gp> prop;
    typedef std::map<std::string, prop> PropertyMap;

public:
    base() {}
    virtual ~base() {}

public:
    bool setProperty(const char* name, int value) {
        std::string str(name);
        PropertyMap::const_iterator i = propMap.find(str);
        ((i->second).first)(value);
        return true;
    }

    int property(const char* name) const {
        std::string str(name);
        PropertyMap::const_iterator i = propMap.find(str);
        return ((i->second).second)();
    }

protected:
    PropertyMap propMap;
    bool register_property(const char* name, sp setprop, gp getprop) {
        return propMap.insert(std::make_pair(std::string(name), prop(setprop, getprop))).second;
    }
};


class base1 : public base
{
public:
    base1() {
        //register_property("TEST",&base1::setTestProp, &base1::getTestProp()); //< ??? Проблема здесь
    }

    bool setTestProp(int val) {
        return true;
    }

    int getTestProp() {
        return 125;
    }
};


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

Можно конечно для каждого метода делать,что-то вроде
static int call_getTestProp(base1& param) {
     return param.getTestProp();
}
и передавать указатель уже этого метода
Но тогда весь смысл в свойствах теряется.
Как быть?


Кто-нибудб делал что-то подобное. Может есть другой способ реализации PROPERTY?

Сообщение отредактировал igor_bogomolov - 30.7.2009, 11:02
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
igor_bogomolov
  опции профиля:
сообщение 30.7.2009, 17:02
Сообщение #2


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


Вот что в результате получилось.
инклюдники и определения
#include <map>
#include <string>
#include <boost/function.hpp>
#include <boost/bind/bind.hpp>
#include <boost/variant.hpp>

using namespace std;
using namespace boost;

/// тип свойства
typedef boost::variant<int, string, double> Property_t;

/**
*  \def   REGISTER_PROPERTY(NAME, SETFUNC, GETFUNC)
*  \brief регистрация свойства экземпляра класса.
*
*  \var NAME    - имя свойства
*  \var SETFUNC - указатель на функцию установки свойства
*  \var GETFUNC - указатель на функцию чтения свойства
*/
#define REGISTER_PROPERTY(NAME, SETFUNC, GETFUNC) { \
    register_property( NAME, boost::bind(&SETFUNC, this, _1), boost::bind(&GETFUNC, this) ); \
}
класс Property
class Property
{
public:
    Property() {}       //!< Конструктор
    virtual ~Property() //!< Деструктор. Чистит все списки свойств
    {
        // а как память коректно очистить ???
        propMap.clear();
    }

public:
    /// Тип указателя на процедуру установки свойства
    typedef boost::function< bool (Property_t) > SetFunc;
    /// Тип указателя на процедуру чтения свойства
    typedef boost::function< Property_t ()     > GetFunc;
    /// Тип пары указателей на сетер и гетер
    typedef std::pair< SetFunc, GetFunc        > Set_Get_Pair;
    /// Тип отображения свойств
    typedef std::map< string, Set_Get_Pair     > PropertyMap;

public:
    /**
     *  \brief   Установить свойство.
     *
     *  \var     name  - имя свойства
     *  \var     value - значение
     *  \return  true при успешной установке свойства, иначе false.
     *  \warning Если свойство не найдено, генерируется исключение
     */
    bool setProperty(const char* name, Property_t value)
    {
        std::string str(name);
        PropertyMap::const_iterator i = propMap.find(str);
        if( i == propMap.end() ) {
            throw std::runtime_error("[setProperty] неизвестное свойство");
        }
        return ((i->second).first)(value);
    }

    /**
     *  \brief   Считать свойство.
     *
     *  \var     name - имя свойства
     *  \return  значение свойства
     *  \warning Если свойство не найдено, генерируется исключение
     */
    Property_t property(const char* name) const {
        std::string str(name);
        PropertyMap::const_iterator i = propMap.find(str);
        if( i == propMap.end() ) {
            throw std::runtime_error("[property] неизвестное свойство");
        }
        return ((i->second).second)();
    }

protected:
    PropertyMap propMap; //!< отображение свойств

    /**
     *  \brief Зарегистрировать свойство.
     *  \return true при удачной регистрации, иначе false
     */
    bool register_property(const char* name, SetFunc setprop, GetFunc getprop) {
        return propMap.insert(std::make_pair(string(name), Set_Get_Pair(setprop, getprop))).second;
    }
};
объявление классов для тестирования
class Test1 : public Property
{
public:
    Test1() {
        REGISTER_PROPERTY("Test", Test1::setTestProp, Test1::getTestProp);
    }
    bool setTestProp(Property_t /*val*/) {
        return true;
    }
    Property_t getTestProp() {
        return 125;
    }
};

class Test2 : public Property
{
public:
    Test2() {
        REGISTER_PROPERTY("Test", Test2::setTestProp2, Test2::getTestProp2);
    }
    bool setTestProp2(Property_t /*val*/) {
        return true;
    }
    Property_t getTestProp2() {
        return "string";
    }
};

class Test3 : public Property
{
public:
    Test3() {
        REGISTER_PROPERTY("Test", Test3::setTestProp3, Test3::getTestProp3);
    }
    bool setTestProp3(Property_t /*val*/) {
        return true;
    }
    Property_t getTestProp3() {
        return 1.89;
    }
};
main
int main(int /*argc*/, char** /*argc*/)
{
    Property* b[] = { new Test1, new Test2,  new Test3 };
    for(int i = 0; i != 3; i++ )
        cout <<"Property_t = " << b[i]->property("Test") << std::endl;

    return EXIT_SUCCESS;
}
результат
Цитата
Property_t = 125
Property_t = string
Property_t = 1.89


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

У меня еще остался вопрос, по поводу очистки памяти в деструкторе. Достаточно ли просто сделать propMap.clear(); ???
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


4 чел. читают эту тему (гостей: 4, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 23.11.2024, 5:39