Re[12]: Рефлексия для бедных...
От: niralex  
Дата: 01.03.12 16:22
Оценка:
Здравствуйте, enji, Вы писали:

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


E>>>Кстати, а чего вы тот-же Qt не заюзаете? Свойства там есть и как раз такие, как вам нужны. Плюс поддержка от ИДЕ и очень хороший хелп


N>>1. По независящим от меня причинам, студентов(основных пользователей этой системы) учат работать в Embarcadero RAD Studio C++Builder. Перейти на QT самостоятельно в сжатые сроки смогут единицы.

N>>2. По "политическим" мотивам предпочитаем разрабатывать свои велосипеды. Проект не коммерческий, в шею никто не гонит, делаем для себя, почему бы и не попробовать...

E>в блдере есть собственные свойства и средства для их рантайм-перебора.

да, но поддержка этих свойств(если имеется ввиду __property) за счет нестандартных средств компилятора и во-вторых слишком громоздко получается.

Е>Кстати, если проект не коммерческий — то каким боком тут рад-студия? она весьма недешевая...

а никто и не покупает... проект для внутреннего использования.

E>Насчет перехода на qt — не надо на него переходить. Достаточно просто заюзать свойства оттуда, а гуй пишите на чем писали

я, конечно, глубоко не вникал в qt, но думаю не так просто вычленить оттуда систему поддержки свойств, во всяком случае для нас.
Re[8]: Рефлексия для бедных...
От: niralex  
Дата: 11.03.12 10:15
Оценка:
После долгих и мучительных размышлений решил остановиться на таком варианте решения своей задачи, которую лучше всего сформулировал Erop:

E>Мы, типа, хотим писать какие-то классы, просто так брать и писать, а потом некоторые из полей этих классов делать доступными через интерфейс, который эти классы поддерживают. На поля мы хотим ссылаться по именам.

E>И мы хотим, чтобы публикация проходила декларативно, а работало всё это безопасно.

using namespace std;
class TComponent;
//---------------------------------------------------------------------------
// базовый класс свойств - обеспечивает доступ к полям классов
class TProperty
{
    public:
        virtual string Type()const=0;              // тип свойства
        virtual void *Value(TComponent * AThis)=0; // значение свойства
};

//---------------------------------------------------------------------------
// пример класса свойств для стандартных типов
typedef TComponent::*TField;

template<class TypeValue>
class TPropSimple : public TProperty
{
    private:
        // указатель на переменную-член класса
        // для которой создается свойство
        TField _field;

    public:
        TPropSimple(TField AField) : _field(AField) {}
        string Type()const { return typeid(TypeValue).name(); }
        void *Value(TComponent * AThis) { return &(AThis->*_field); }
};

//---------------------------------------------------------------------------
// базовый класс компонентов
class TComponent
{
    private:

        typedef std::map<string, boost::shared_ptr<TProperty>, less<string> > TMapProperty;

        // синглетон контейнера свойств класса
        static TMapProperty &Props()
        {
            static TMapProperty _props;
            return _props;
        }

    protected:
        static void PushProp(const string& AName, TProperty *AProp)
        {
            Props()[AName] = boost::shared_ptr<TProperty>(AProp);
        }

    public:
        // интерфейс доступа к свойствам объекта
        static int CountProperties() { return Props().size(); }

        static vector<string> AllPropNames() // список имен всех свойств
        {
            vector<string> _pnames;
            for(TMapProperty::const_iterator i = Props().begin(); i != Props().end(); i++)
                _pnames.push_back( i->first );
            return _pnames;
        }

        static string PropertyType(string AName) { return Props()[AName]->Type(); }

        template<class Type>
        Type &PropertyAs(string AName){ return *((Type*)Props()[AName]->Value(this)); }
};

//---------------------------------------------------------------------------
// макросы для декларации свойств в пользовательсках классах
#define BEGIN     static void Constructor() {
#define PROP_INT(FIELD, NAME) TComponent::PushProp(NAME, new TPropSimple<int>((TField)&FIELD) );
#define PROP_FLOAT(FIELD, NAME) TComponent::PushProp(NAME, new TPropSimple<float>((TField)&FIELD) );
#define END }

//---------------------------------------------------------------------------
// вспомагательный класс, обеспечивающий автоматический вызов статической функии
// Type::Conctructor() у класса-наследника, которая в свою очередь создает все
// свойства класса
template<class Type>
class TComIniter : public TComponent
{
    static struct TClasIniter
    {
        TClasIniter() { Type::Constructor(); }
    } _initer;

    // вспомагательная функция, необходимая для того, чтобы компилятор
    // инстанцировал статическую переменную _initer
    virtual void f() {    (void)_initer;    }
};

// инстанцирование статической переменной класса _initer
template<class Type>
typename TComIniter<Type>::TClasIniter TComIniter<Type>::_initer;

//---------------------------------------------------------------------------
// пример пользовательского класса
class TDemo : public TComIniter<TDemo>
{
    private:
        int x;
        float y;

    public:
        // декларация свойств класса
        BEGIN
           PROP_INT(x, "x");
           PROP_FLOAT(y, "y");
        END
};
//----------------------------------------------------------------------------------
// пример использования
int main()
{
    vector<string> props(TDemo::AllPropNames());
    cout << "All properties: " << TDemo::CountProperties() << endl;
    for(int i = 0; i < props.size(); i++)
        cout << props[i].c_str() << ": "
             <<    TDemo::PropertyType(props[i]).c_str() << endl;

    TComponent *Ob1(new TDemo);
    Ob1->PropertyAs<int>("x") = 1;
    float &y = Ob1->PropertyAs<float>("y");
    y = 1.1;
    cout << Ob1->PropertyAs<int>("x") << endl;    // 1
    cout << y << endl;  // 1.1
    delete Ob1;
    getchar();
    return 0;
}


В решении использованы идеи и кодинг Erop-а(спасибо, оказались очень полезными)
и старый топик о конструкторах класса
Автор: remark
Дата: 03.09.08

В связи с недостаточностью моих знаний и практики в области С++, многие из предложенных другими участниками решений не подошли по банальной причине — не смог их понять
Приведенное решение не окончательное. Если кто-то видит потенциальные проблемы, ошибки и т.д., буду рад услышать об этом.
Re[9]: Рефлексия для бедных...
От: Анатолий Широков СССР  
Дата: 11.03.12 11:34
Оценка:
N>Приведенное решение не окончательное. Если кто-то видит потенциальные проблемы, ошибки и т.д., буду рад услышать об этом.

А зачем же так многословно-то? тынц
Автор: Анатолий Широков
Дата: 28.01.05
Re[9]: Рефлексия для бедных...
От: MasterZiv СССР  
Дата: 11.03.12 12:01
Оценка:
On 03/11/2012 02:15 PM, niralex wrote:

> // базовый класс свойств — обеспечивает доступ к полям классов


> class TProperty

> {
> public:
> virtual string Type()const=0; // тип свойства
> virtual void *Value(TComponent * AThis)=0; // значение свойства
> };


Ну, после всего что тут было понаписано, возвращать void* как-то уж совсем ...
Не С++ way.
Posted via RSDN NNTP Server 2.1 beta
Re[10]: Рефлексия для бедных...
От: niralex  
Дата: 11.03.12 14:24
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

N>>Приведенное решение не окончательное. Если кто-то видит потенциальные проблемы, ошибки и т.д., буду рад услышать об этом.


АШ>А зачем же так многословно-то? тынц
Автор: Анатолий Широков
Дата: 28.01.05


В твоем решении я вижу две проблемы:
1) имена полей не статические, т.е. каждый объект класса будет хранить свою копию std::map<std::string, boost::any> property; Это, как минимум нерационально.

2) Например, есть уже написанный класс и нужно сделать из него компонент, т.е. сделать свойства из уже существующих полей. В моем решении я только добавлю наследование от TComIniter<Type> и макросы BEGIN...END. Все. При этом размер объектов не увеличится. В твоем случае будет сложнее... Хочется, чтобы класс можно было писать не думая о том, что там будут какие-то свойства, а потом просто дополнить чем-то по-минимуму, чтобы появились свойства.
Re[10]: Рефлексия для бедных...
От: niralex  
Дата: 11.03.12 14:57
Оценка:
Здравствуйте, MasterZiv, Вы писали:

>> // базовый класс свойств — обеспечивает доступ к полям классов


>> class TProperty

>> {
>> public:
>> virtual string Type()const=0; // тип свойства
>> virtual void *Value(TComponent * AThis)=0; // значение свойства
>> };


MZ>Ну, после всего что тут было понаписано, возвращать void* как-то уж совсем ...

MZ>Не С++ way.


Да, в целом согласен. В оправдание могу только сказать, что это все это спрятано "внутри", т.е. клиентский код не работает с viod* напрямую, а использует медод PropertyAs<Type>(string), куда можно добавить всякие проверки, assert-ы и т.д и пполучить свой велосипед. Во вторых, в моем проекте есть своя специфика — все пользовательские классы помещаются в dll-ки, для чего классы "заворачиваются" в С-оболочку(понимаю, что звучит дико). Там естественно используется void*, что красиво стыкуется с приведенным кодом. Ну и главное — я не работал никогда с boost::any или boost::variant и есть предубеждение, что использование подобных штук(если они имелись в виду) скажется на размере/производительности/удобстве использования. Или я не прав?
Re[11]: Рефлексия для бедных...
От: Анатолий Широков СССР  
Дата: 11.03.12 15:14
Оценка:
N>Да, в целом согласен. В оправдание могу только сказать, что это все это спрятано "внутри", т.е. клиентский код не работает с viod* напрямую, а использует медод PropertyAs<Type>(string), куда можно добавить всякие проверки, assert-ы и т.д и пполучить свой велосипед. Во вторых, в моем проекте есть своя специфика — все пользовательские классы помещаются в dll-ки, для чего классы "заворачиваются" в С-оболочку(понимаю, что звучит дико). Там естественно используется void*, что красиво стыкуется с приведенным кодом. Ну и главное — я не работал никогда с boost::any или boost::variant и есть предубеждение, что использование подобных штук(если они имелись в виду) скажется на размере/производительности/удобстве использования. Или я не прав?

В общем случае, при выборе средств "предубеждение" должно быть последним на чаша весов "за" или "против". А так, как и в любой исследовательской работе, сначала изучаешь, что уже есть, выделяешь достоинства и недостатки, проводишь эксперименты с целью выявить осязаемые метрики, дабы при сравнении оперировать конкретными "цифирями". Это все общие слова, конечно. В своих проектах отдавал и отдаю предпочтение средствам стандартным и хорошо специфицированным.
Re[11]: Рефлексия для бедных...
От: MasterZiv СССР  
Дата: 11.03.12 20:00
Оценка:
> красиво стыкуется с приведенным кодом. Ну и главное — я не работал никогда с
> boost::any или boost::variant и есть предубеждение, что использование подобных
> штук(если они имелись в виду)

Я имел в виду не их, что-то типа свойств на шаблонах.

скажется на размере/производительности/удобстве

На удобстве конечно скажется. А на размер и производительность, думаю, тебе
обращать внимание не нужно.
Posted via RSDN NNTP Server 2.1 beta
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.