Может ли объект "узнать" где он создается?
От: niralex  
Дата: 21.02.12 17:01
Оценка:
Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):

class B;
class A
{
   public:
      A()
      {
          /* здесь нужно получать указатель на родительский объект или NULL, если объект создается глобально*/
      }
};
class B
{
   public:
      A a1;
};


Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме.
Re: Может ли объект "узнать" где он создается?
От: Vamp Россия  
Дата: 21.02.12 17:28
Оценка: 2 (1) +1
N>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):
Полагаю, что никак. Более того, к моменту вызова конструктора внутреннего класса внешний еще не создан — и смысла в этом указателе в практическом плане я не вижу.
Да здравствует мыло душистое и веревка пушистая.
Re: Может ли объект "узнать" где он создается?
От: Константин Россия  
Дата: 21.02.12 17:52
Оценка:
Здравствуйте, niralex, Вы писали:


N>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):

N>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме.

Интересно, а что за задача решается?
Re: Может ли объект "узнать" где он создается?
От: MasterZiv СССР  
Дата: 21.02.12 18:31
Оценка: 2 (1)
> Можно ли в конструкторе объекта без параметров каким-либо образом
> получить указатель на объект в котором он создается (в случае композиции):

Нельзя.

> Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно

> почитать по теме.

Решение простое -- сделай соотв. конструктор, вызывай его в "родителе",
передавай "ребёнку" ссылку на "родителя".
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 21.02.12 19:10
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Нельзя.


MZ>Решение простое -- сделай соотв. конструктор, вызывай его в "родителе",

MZ>передавай "ребёнку" ссылку на "родителя".

это решение понятно, но я искал решение без передачи параметра в конструктор.
Re[3]: Может ли объект "узнать" где он создается?
От: MasterZiv СССР  
Дата: 21.02.12 19:58
Оценка:
> MZ>Решение простое -- сделай соотв. конструктор, вызывай его в "родителе",
> MZ>передавай "ребёнку" ссылку на "родителя".
>
> это решение понятно, но я искал решение без передачи параметра в конструктор.

Тебе же сказали, в рамках языка С++ нет. можешь искать дальше, конечно, дело твоё.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 21.02.12 21:31
Оценка:
Спасибо всем за ответы.

Здравствуйте, Константин, Вы писали:

К>Интересно, а что за задача решается?



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

В одном из решений задачи, которое используется в данный момент, все классы рассмотриваются как контейнеры специальных объектов-свойств, которые в общем случае являются простыми оболочками для стандартных типов.
Это выглядит примерно так:

class Property // базовый класс свойств
{
    public:
        string Name;   // имя свойства
        // ...
        Property(string AName) : Name(AName) {}
};
class IntProperty : public  Property // свойство-оболочка для типа int
{
    private:
        int _value;
    public:
        IntProperty(string AName, int AValue) : Property(AName), _value(AValue) {}
        int &Value() { return _value; } // доступ к значению свойства
};

class BaseComponent // базовый класс иерархии компонентов
{
    protected:
        std::vector<Property*>  _props; // свойства компонента
    public:
        // обобщенный интерфейс, наследуемый потомками
                int CountProperties()const { return _props.size(); }
        Property *GetProperty(int AIndex) { return _props[AIndex]; }
};
// пример класса иерархии
class ComponentExample : public BaseComponent
{
    private:
       // специфические данные компонента
       IntProperty _data; // вместо int _data;

    public:
       ComponentExample() : _data("NameProperty", 0)
       {
           _props.push_back(&_data); // 1
       }
       // специализированный интерфейс компонента
           // ...


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

Возникла идея, чтобы конструкторы классов свойств сами себя добавляли в контейнер _props. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?
Re[3]: Может ли объект "узнать" где он создается?
От: night beast СССР  
Дата: 22.02.12 03:58
Оценка:
Здравствуйте, niralex, Вы писали:

N>Возникла идея, чтобы конструкторы классов свойств сами себя добавляли в контейнер _props. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?


здесь
Автор: enji
Дата: 20.02.12
Re[4]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 22.02.12 06:34
Оценка:
Здравствуйте, night beast, Вы писали:

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


N>>Возникла идея, чтобы конструкторы классов свойств сами себя добавляли в контейнер _props. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?


NB>здесь
Автор: enji
Дата: 20.02.12

Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.
Re[3]: Может ли объект "узнать" где он создается?
От: Erop Россия  
Дата: 22.02.12 08:22
Оценка: 3 (1)
Здравствуйте, niralex, Вы писали:

N>Требуется разработать базовый класс иерархии, который бы обеспечивал обобщенный унифицированный интерфейс доступа ко всем объектам иерархии. При этом количество классов велико, классы разрабатываются разными людьми для разных задач. Под доступом понимается возможность обращаться к членам классов для чтения/изменения значений. Другими словами, каждый класс должен иметь два интерфейса, один из котороых обощенный, чтобы со всеми объектами можно было работать однотипно.


N>В одном из решений задачи, которое используется в данный момент, все классы рассмотриваются как контейнеры специальных объектов-свойств, которые в общем случае являются простыми оболочками для стандартных типов.


А нужно иметь возможность создавать одинокие свойства? Которые не лежат в контейнере?
А то можно же просто добавить в конструктор свойства BaseComponent*, и всё сразу заиграет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Может ли объект "узнать" где он создается?
От: night beast СССР  
Дата: 22.02.12 08:55
Оценка: 2 (1)
Здравствуйте, niralex, Вы писали:

N>>>Возникла идея, чтобы конструкторы классов свойств сами себя добавляли в контейнер _props. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?


NB>>здесь
Автор: enji
Дата: 20.02.12

N>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.

то есть, как реализована там передача информации о родителе ты посмотрел?
Re: Может ли объект "узнать" где он создается?
От: gegMOPO4  
Дата: 22.02.12 09:46
Оценка: 2 (1) -1
21.02.12 19:01, niralex написав(ла):
> Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):

[perversion mode on]
Контейнер наследуется от базового класса, который сохраняет ссылку на
себя в глобальной переменной. Компонента проверяет эту ссылку в
конструкторе и сбрасывает её.

Разумеется, есть множество случаев, когда это «работать» не будет.
[perversion mode off]
Posted via RSDN NNTP Server 2.1 beta
Re: Может ли объект "узнать" где он создается?
От: denisko http://sdeniskos.blogspot.com/
Дата: 22.02.12 10:43
Оценка: :)
Здравствуйте, niralex, Вы писали:


N>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме. C чем связано требование про без параметров? Если требование не строгое, а нужно, чтобы объект просто вел себя как будто у него есть конструктор без параметров, то можно передавать туда значения по умолчанию. Типа такого


//какая фигня описывающая контекст
struct Context
{
   int a;
};

//получение контекста, вся логика обработки именно в этой функции
Context* getGlobalContext()
{
   return NULL;
}
//многострадальная пропертя
struct PropertyType
{
   PropertyType(Context* c = getGlobalContext())
   {
    ;
   }
   ~PropertyType()
   {
      ;
   }
   int b;
};
<Подпись удалена модератором>
Re[2]: Может ли объект "узнать" где он создается?
От: denisko http://sdeniskos.blogspot.com/
Дата: 22.02.12 12:42
Оценка:
Здравствуйте, denisko, Вы писали:

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



N>>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме. C чем связано требование про без параметров? Если требование не строгое, а нужно, чтобы объект просто вел себя как будто у него есть конструктор без параметров, то можно передавать туда значения по умолчанию. Типа такого

Кстати подумал, есть еще грязный способ через переопределение unexpected (тогда и никаких параметров не надо передавать вообще), но он, работает только в теории, и слава богу.
<Подпись удалена модератором>
Re[4]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 22.02.12 17:03
Оценка:
Здравствуйте, Erop, Вы писали:

E>А нужно иметь возможность создавать одинокие свойства? Которые не лежат в контейнере?

E>А то можно же просто добавить в конструктор свойства BaseComponent*, и всё сразу заиграет...

Одинокие свойства не нужны. Считается, что они неотделимы от компонента.
Если я правильно понял мысль, то конструкторы свойств должны быть такими:
SomeProperty::SomeProperty(BaseComponent* Parent){}

а компонент будет обязан передавать this при создании свойства.
Такой вариант рассматривается, он всем хорош, но пугает небольшая проблема — вдруг кто-то передаст вместо this, указатель на какой-нибудь другой компонент...
Re[6]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 22.02.12 17:08
Оценка:
Здравствуйте, night beast, Вы писали:

NB>>>здесь
Автор: enji
Дата: 20.02.12

N>>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.

NB>то есть, как реализована там передача информации о родителе ты посмотрел?


нет, глубоко не вник, при поверхностном рассмотрении показалось что не то, извиняюсь.
Сейчас пытаюсь разобраться, но сложновато для моего уровня...
Re[2]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 22.02.12 17:28
Оценка:
Здравствуйте, gegMOPO4, Вы писали:

MOP>[perversion mode on]

MOP>Контейнер наследуется от базового класса, который сохраняет ссылку на
MOP>себя в глобальной переменной. Компонента проверяет эту ссылку в
MOP>конструкторе и сбрасывает её.

MOP>Разумеется, есть множество случаев, когда это «работать» не будет.

MOP>[perversion mode off]

Согласен, это решает и тоже рассматривается как вариант. Я даже писал рабочий набросок кода который все это реализует, правда немного усовершенствованный — для создания компонента используется глобальная функция, которая сбрасывает глобальный указатель, чтобы это не "забывали" делать компоннеты. Но в этом варианте не нравится использование глобальной переменной. Например, как быть, если в компоненте создается вложенный компонент(хотя это можно попробовать решить через стек глобальных указателей на компоненты, которые создаются в данный момент) или что будет в многопоточном приложении, где каждый объект содает свои компоненты? В целом, чувствую, что как-то это все не так...
Re[7]: Может ли объект "узнать" где он создается?
От: night beast СССР  
Дата: 22.02.12 19:03
Оценка:
Здравствуйте, niralex, Вы писали:

N>Здравствуйте, night beast, Вы писали:


NB>>>>здесь
Автор: enji
Дата: 20.02.12

N>>>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.

NB>>то есть, как реализована там передача информации о родителе ты посмотрел?


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

N>Сейчас пытаюсь разобраться, но сложновато для моего уровня...

если в двух словах, то для каждого свойства генерируется свой класс вида:
struct Container 
{
  struct Property_UNIQUEID
  {
    Container * parent ( ) { 
      return reinterpret_cast<Container *>( reinterpret_cast<char *>(this) - offsetof(Container,value) );
    }
  } value;   
};

int main ( )
{
   Container x;
   std::cout << &x << "==" << x.value.parent( ) << std::endl;
}
Re[3]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 22.02.12 20:39
Оценка:
Всем спасибо за помощь! Полезной информации получил много, буду переваривать.
Re[5]: Может ли объект "узнать" где он создается?
От: Erop Россия  
Дата: 22.02.12 21:58
Оценка: 3 (1)
Здравствуйте, niralex, Вы писали:

N>Такой вариант рассматривается, он всем хорош, но пугает небольшая проблема — вдруг кто-то передаст вместо this, указатель на какой-нибудь другой компонент...


Ну у него и не взлетит...

Но тут можно зайти ещё и с другой стороны.
#include <map>
#include <string>

struct INamedProperty {
    const std::string Name;

    INamedProperty( const std::string& name_ ) : Name( name_ ) {}
    virtual ~INamedProperty() {}
};

template<typename T>
class CNamedProperty : public INamedProperty {
    T data;
public:
    CNamedProperty( const std::string name_ ) : INamedProperty( name_ ), data( T() ) {}
    
    T& Get() { return data; }
    template<typename Y> operator Y() { return data; }
};

class CPropertiesSet {
public:
    INamedProperty* GetIProperty( const std::string& name ) 
    {
        propertiesStorage_t::iterator p = properties.find( name );
        return p != properties.end() ? p->second : 0;
    }
    
    template<typename T>
    CNamedProperty<T>* GetProperty( const std::string& name ) 
        { return dynamic_cast<CNamedProperty<T>*>( GetIProperty( name ) ); }

    template<typename T>
    T& GetPropertyData( const std::string& name ) 
        { return GetProperty<T>( name )->Get(); }

protected:
    CPropertiesSet() {}
    virtual ~CPropertiesSet() 
    {
        for( propertiesStorage_t::iterator p = properties.begin(); p != properties.end(); ++p ) {
            setPropertyPtr( p->second, 0 ); 
        }
    }

    template<typename T> T& addProperty( const std::string& name )
    {
        CNamedProperty<T>* p = new CNamedProperty<T>( name );
        properties[name] = p;
        return p->Get();
    }
private:
    typedef std::map<std::string, INamedProperty* > propertiesStorage_t;
    propertiesStorage_t properties;

    CPropertiesSet( const CPropertiesSet& );
    void operator = ( const CPropertiesSet& );
    static void setPropertyPtr( INamedProperty*& dst, INamedProperty* toSet )
    {
        if( dst != toSet ) {
            std::swap( dst, toSet );
            delete toSet;
        }
    }


};
///////////////////////////

struct TestClass : CPropertiesSet {
    int& X;
    std::string& Y;

    TestClass() : 
        X( addProperty<int>( "X" ) ), 
        Y( addProperty<std::string>( "Y" ) )
    {
    }

    static int testIt()
    {
        TestClass x;
        x.GetPropertyData<int>( "X" ) = 5;
        return x.X;
    }
};
типа свойства вообще всегда хрянятся внутри базы, а в нследниках если надо, запонимают ссылки на нужные переменные.
Кстати, при таком подходе, я бы ещё и имена у пропертей поубирал, зачем они им? По идее, имя должно знасть множество.

А у вас множественное наследование бывает?

На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип, а не на экземпляр...
Так и быстрее и веселее должно быть.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 23.02.12 09:19
Оценка:
Здравствуйте, Erop, Вы писали:
E>А у вас множественное наследование бывает?

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

Расскажу о проекте, чтобы требования были лучше понятны и не выглядели надуманными. Система не
коммерческая и используется для научно-исследовательских работ студентов. Например, поставлена
задача для группы студентов: "Использование искусственных нейронных сетей для прогнозирования
временных рядов". Студент должен исследовать разные виды нейронных сетей, алгоритмов обучения,
влияние на результат различных параметров обучающей выборки шаблонов и т.д. У студентов есть
несколько вариантов организации своей работы: воспользоваться матлабом, специализированным ПО
или реализовать все эксперименты самому на С++. По ряду причин последний вариант наиболее
эффективный при условии хорошего владения средствами языка. Вот в этом и проблема. Группе
студентов тяжело все разработать и запрограммировать "с нуля" в условиях постоянно меняющихся
требований(постоянно появляются новые идеи), отсутвия должных навыков групповой работы, да и
вообще опыта разработки ПО. Для решения этих проблем и была разработана описываемая система.
Теперь так — студентам дается образец кода одного из компонентов и
поясняются несложные правила написания компонентов(от какого класса наследовать, как определять
свойства, связи и действия), а также готовая главная программа. Каждому дается своя задача на
разработку компонента(ов), например кто-то делает компонент NuralNetwork, кто-кто
GeneticAlgorihtm, кто-то Crossover, кто-то Patterns и т.д. Затем в основной прогармме это все
связывается и запускается. Если появилась идея, типа "а давайте попробуем полносвязную нейронную
сеть...", деаем еще один компонент, меняем одну связь в главной программе и смотрим на
результат. Кроме этого есть уже готовые компоненты, написанные "предыдущими покаолениями"
студентов. Когда получаем приемлемый результат исследований, то компонент может быть легко заюзан в отдельном
демонстрационном или рабочем приложении. Главное что мы получили — четкое разделение, повторное
использование кода и скорость реализации идей. Текущая проблема с системой — большое количество
глюков в компонентах из-за непрофессионализма разработчиков. Насущная задача — доработка системы
таким образом, чтобы студентам было как можно проще создавать компоненты и оставалось как можно
меньше возможностей для ошибок, а те что все же допущены можно бы было лекго обнаруживать при
общем тестировании компонента до того, как он будет использоваться.

E>На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип,

а не на экземпляр...
E>Так и быстрее и веселее должно быть.

Согласен, но как это красиво реализовать. Ведь такие параметры свойств, как имя, атрибут "только
для чтения" и другое относятся к типу, а значение свойства — у каждого объекта свое.
Re[7]: Может ли объект "узнать" где он создается?
От: MasterZiv СССР  
Дата: 23.02.12 09:29
Оценка: +1
On 02/23/2012 01:19 PM, niralex wrote:

> Нет, даже композиции нет. Концепция такая — компоненты состоят только из свойств,

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

По-моему простой список свойств тут подошёл бы лучше.
Плюс возможно объект-flyweigh для реализации логики работы с этими свойствами.
Posted via RSDN NNTP Server 2.1 beta
Re[8]: Может ли объект "узнать" где он создается?
От: B0FEE664  
Дата: 23.02.12 10:11
Оценка:
Здравствуйте, night beast!

Хочу заметить, что согласно стандарту (в новом это 18.2.4) макрос offsetof применим только к standard-layout class и поэтому (IMHO) данный прием niralex'у не подходит.
И каждый день — без права на ошибку...
Re[8]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 23.02.12 13:22
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>On 02/23/2012 01:19 PM, niralex wrote:


>> Нет, даже композиции нет. Концепция такая — компоненты состоят только из свойств,

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

MZ>По-моему простой список свойств тут подошёл бы лучше.

MZ>Плюс возможно объект-flyweigh для реализации логики работы с этими свойствами.

не понял идею, можно подробнее. Что такое паттерн flyweigh представление имею.
Re[9]: Может ли объект "узнать" где он создается?
От: MasterZiv СССР  
Дата: 24.02.12 09:11
Оценка:
> MZ>По-моему простой список свойств тут подошёл бы лучше.
> MZ>Плюс возможно объект-flyweigh для реализации логики работы с этими свойствами.
>
> не понял идею, можно подробнее. Что такое паттерн flyweigh представление имею.
> Re[8]: Может ли объект "узнать" где он создается? <message/4631013.aspx>


Ну пример кода твоего класса покажи ...
Posted via RSDN NNTP Server 2.1 beta
Re[7]: Рефлексия для бедных...
От: Erop Россия  
Дата: 24.02.12 11:46
Оценка: 3 (1)
Здравствуйте, niralex, Вы писали:

E>>На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип,

N>а не на экземпляр...
E>>Так и быстрее и веселее должно быть.

N>Согласен, но как это красиво реализовать. Ведь такие параметры свойств, как имя, атрибут "только

N>для чтения" и другое относятся к типу, а значение свойства — у каждого объекта свое.

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

Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.

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

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

Первое, что нам понадобится -- это способ как-то сослаться на данные неизвестного типа. Это должно быть копируемое данное, которое можно вернуть из функции и потом у него расспросить, что за тип там внутри, прочитать, записать и т. д.
Есть много разных библиотек, которые решают эту задачу по всякому, так что я не буду заострять внимание на этом всём подробно. Просто напишу какой-то DataRef для бедных. А для реальных задач уже можно будет сделать хорошо, или взять библиотечный.

Итак, к вашим услугам относительно безопасный void* :
#include <assert.h>
#include <vector>
#include <map>
#include <string>
////////////////////////////////////////////////////////////////
//  TestDataRef
class DataRef {
    const type_info& type;
    void* const dataPtr;
public:
    DataRef() : type( typeid( void ) ), dataPtr( 0 ) {}
    template<typename T> 
    DataRef( T& data ) : type( typeid( T ) ), dataPtr( &data ) { assert( dataPtr != 0 ); }
    bool IsNull() const { return dataPtr == 0; }
    
    template<typename T> 
    bool CheckType() { return type == typeid( T ); }
    template<typename T> 
    bool CheckType( const T& ) { return CheckType<T>(); }
    
    template<typename T> 
    T& GetRef() 
    { 
        assert( CheckType<T>() && dataPtr != 0 ); 
        return *static_cast<T*>( dataPtr );
    }
    
    template<typename T> 
    operator T&() { return GetRef<T>(); }

    template<typename T>
    void operator = ( const T& t ) { GetRef<T>() = t; }

};

Вот пример, как это работает:
////////////////////////////////////////////////////////////////
//  TestDataRef

template<typename T>
bool SetAs( DataRef r, const T& val )
{
    const bool res = r.CheckType( val );
    if( res ) {
        r = val;
    }
    return res;
}

bool TestDataRef()
{
    int x = 0;
    std::string y = "vava";

    DataRef dInt( x );
    DataRef dStr( y );
    
    const std::string testText( "qqq" );

    return 
        SetAs( dInt, 5 ) &&
        !SetAs( dInt, testText ) &&
        ! SetAs( dStr, 5 ) &&
        SetAs( dStr, testText ) &&
        x == 5 && y == testText;
}

///////////////////////////////////////////////////////////////

У меня, на VC 2008 TestDataRef() возвращает true.

Теперь, когад у нас есть, что возвращать из методов того самого интерфейса, мы можем его описать и попробовать реализовать:
////////////////////////////////////////////////////////////////
//    MappedFieldsOf

//    Тот самый интерфейс
class IMappedValues {
public:
    virtual std::vector<std::string> GetAllNames() = 0;
    virtual DataRef GetValue( const std::string& name ) = 0;
    template<typename T> T& GetRef( const std::string& name ) 
    {
        DataRef ref = GetValue( name );
        assert( !ref.IsNull() && ref.CheckType<T>() );
        return ref;
    }
protected:
    virtual ~IMappedValues() {}
};

//    Макросы для декларации публикуемых полей класса. пишутся прямо внутри определения класса
#define FIELD_MAPPING_BEGIN( THE_CLASS ) \
public:\
    static void constructMapOfFieldsPrivateFunction( MappedFieldsOf<TestClass>::MapOfDescriptors* dst_ ) \
    { \
        typedef TestClass TheClass_; \
        typedef MappedFieldsOf<TheClass_> MappedFieldsOfTheClass_; \
        typedef const MappedFieldsOfTheClass_::IFieldDescriptor& FieldDesc_; \

#define MAP_FIELD_EXT( FIELD, NAME ) \
    { \
        static FieldDesc_ tmp_ = MappedFieldsOfTheClass_::getFieldDescriptorImpl( &TheClass_::FIELD ); \
        dst_->Push( NAME, &tmp_ ); \
    }

#define MAP_FIELD( FIELD ) MAP_FIELD_EXT( FIELD, #FIELD )


#define FIELD_MAPPING_END() \
    }


template<typename TClass> 
class MappedFieldsOf : public IMappedValues {
public:
    virtual std::vector<std::string> GetAllNames()
    {
        return getMapOfFieldsDescriptors().GetAllNames();
    }
        
    virtual DataRef GetValue( const std::string& name )
    {
        const IFieldDescriptor* res = getMapOfFieldsDescriptors().Find( name );
        return res != 0 ? res->GetFieldOf( static_cast<TClass*>( this ) ) : DataRef();
    }
protected:
    
    class IFieldDescriptor {
    public:
        virtual DataRef GetFieldOf( TClass* ) const { return DataRef(); }
    };
    
    template<typename TField>
    class FieldDescriptorImpl : public IFieldDescriptor {
        TField TClass::*const fieldPtr;
    public:
        FieldDescriptorImpl( TField TClass::*ptr ) : fieldPtr( ptr ) { assert( ptr != 0 ); }
        virtual DataRef GetFieldOf( TClass* theThis ) const 
        { 
            assert( theThis != 0 );
            return DataRef( theThis->*fieldPtr ); 
        }
    };

    template<typename TField>
    static FieldDescriptorImpl<TField> getFieldDescriptorImpl( TField TClass::*ptr ) { return ptr; }
    class MapOfDescriptors;
private:
    static const class MapOfDescriptors {
    public:
        MapOfDescriptors( void (*f)( MapOfDescriptors* ) ) { f( this ); }
        
        const IFieldDescriptor* Find( const std::string name ) const
        {
            storage_t::const_iterator p = storage.find( name );
            return p != storage.end() ? p->second : 0;
        }
        void Push( const std::string& name, const IFieldDescriptor* desc )
        {
            assert( desc != 0 );
            storage[name] = desc;
        }
        std::vector<std::string> GetAllNames() const
        {
            std::vector<std::string> res;
            for( storage_t::const_iterator i = storage.begin(); i != storage.end(); ++i ) {
                res.push_back( i->first );
            }
            return res;
        }
    private:
        typedef std::map<std::string, const IFieldDescriptor*> storage_t;
        storage_t storage;

    }& getMapOfFieldsDescriptors()
    {
        static MapOfDescriptors m( TClass::constructMapOfFieldsPrivateFunction );
        return m;
    }
};
Ну и напишем теперь пример использования:
////////////////////////////////////////////////////////////////
//  TestMappedFieldsOf


class TestClass : public MappedFieldsOf<TestClass> {
    FIELD_MAPPING_BEGIN( TestClass )
        MAP_FIELD( X )
        MAP_FIELD_EXT( Y, "YStr" )
    FIELD_MAPPING_END()
public:
    int X;
    std::string Y;

};

bool TestMappedFieldsOf()
{
    TestClass x;
    x.X = 7;
    IMappedValues* mf = &x;
    const std::string testText( "qqq" );

    std::vector<std::string> names = mf->GetAllNames();
    int count = 0;
    for( size_t i = 0; i < names.size(); ++i ) {
        count += SetAs( mf->GetValue( names[i] ), 5 );
        count += SetAs( mf->GetValue( names[i] ), testText );
    }
    return x.X == 5 && x.Y == testText && count == names.size();
}
У меня, на том же компиляторе, TestMappedFieldsOf() возвращает true


Тут всё сделано довольно прямо, есть несколько смонительных мест.
Место 1 -- синглетон Майерса, используемый для хранения отображения на класс. Недостатки такие, что в наивной реализации не дружит с многопоточным окружением + если обратиться слишком поздно, то может уже быть разрушен.
Лечится известно как.

Место 2 -- Юзается вот какой трюк:
int bCount = 0;

class A { public: int a; };
class B : public A { 
public: 
    B() {}
    ~B() 
    { 
        bCount++; 
    }
    mutable int b; 
};

int& foo()
{
    static const A& a = B();  // !!!
    return static_cast<const B&>( a ).b;
    assert( bCount == 0 );
}

bool testIt() 
{
    foo() = 6;
    foo() = 3;
    return foo() == 3 && bCount == 0;
}
Обрати внимание на строку // !!!
Мы там создаём временный объект — наследник, и продлеваем ему время жизни при помощи статической сонстантной ссылки на базу. Это позволяет нам не указывать при регистрации поля его тип, а выводить его...

Собсвтенно вот.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Рефлексия для бедных...
От: niralex  
Дата: 24.02.12 20:15
Оценка:
Здравствуйте, Erop, Вы писали:

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


E>>>На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип,

N>>а не на экземпляр...
E>>>Так и быстрее и веселее должно быть.

N>>Согласен, но как это красиво реализовать. Ведь такие параметры свойств, как имя, атрибут "только

N>>для чтения" и другое относятся к типу, а значение свойства — у каждого объекта свое.

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


"Встроенная" поддержка не всегда подходит... или мы не до конца с ней раобрались

E>Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.


Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код, и пугают, конечно, макросы (почему-то всегда старался их избегать). В любом случае сасибо за внимание к моим проблемам. Честно говоря впечатлен уровнем профессионализма и отзывчивостью лично вашими и других экспертов. Подобного отношения к новичкам не встречал нигде.
Re[9]: Рефлексия для бедных...
От: Erop Россия  
Дата: 24.02.12 23:30
Оценка:
Здравствуйте, niralex, Вы писали:

N>Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код,

Можно как-то поменять DataRef, тем более, что DataRef достаточно на коленке написана тут.
Ну и, нсколько я понял, у вас всё время пишутся новые компоненты

N>и пугают, конечно, макросы (почему-то всегда старался их избегать).

Ну это да. И правильно старался (тут принято на "ты" обращаться к коллегам).
Но тут на компромисс некий приходится идти, так как при таком подходе сложнее допустить ошибку.

Правда там у меня есть ошибка в макросе. В FIELD_MAPPING_BEGIN( THE_CLASS ) вместо typedef TestClass TheClass_; должно быть typedef THE_CLASS TheClass_; \

Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Может ли объект "узнать" где он создается?
От: enji  
Дата: 28.02.12 05:49
Оценка:
Здравствуйте, niralex, Вы писали:

NB>>здесь
Автор: enji
Дата: 20.02.12

N>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.

Ну и что? Идея точно такая-же — из this свойства и имени класса-контейнера получаете указатель на класс-контейнер, и вызываете метод registerProperty()
Re[9]: Рефлексия для бедных...
От: enji  
Дата: 28.02.12 05:55
Оценка: 2 (1)
Здравствуйте, niralex, Вы писали:

E>>Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.


N>Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код, и пугают, конечно, макросы (почему-то всегда старался их избегать). В любом случае сасибо за внимание к моим проблемам. Честно говоря впечатлен уровнем профессионализма и отзывчивостью лично вашими и других экспертов. Подобного отношения к новичкам не встречал нигде.


Кстати, а чего вы тот-же Qt не заюзаете? Свойства там есть и как раз такие, как вам нужны. Плюс поддержка от ИДЕ и очень хороший хелп
Re[7]: Может ли объект "узнать" где он создается?
От: Tonal- Россия www.promsoft.ru
Дата: 28.02.12 11:03
Оценка: 3 (1)
Здравствуйте, niralex, Вы писали:
N>Расскажу о проекте, чтобы требования были лучше понятны и не выглядели надуманными. Система не
N>коммерческая и используется для научно-исследовательских работ студентов. Например, поставлена
N>задача для группы студентов: "Использование искусственных нейронных сетей для прогнозирования
N>временных рядов". Студент должен исследовать разные виды нейронных сетей, алгоритмов обучения,
N>влияние на результат различных параметров обучающей выборки шаблонов и т.д. У студентов есть
N>несколько вариантов организации своей работы: воспользоваться матлабом, специализированным ПО
N>или реализовать все эксперименты самому на С++.
Немного не в тему, но наверное тебе будет интересно посмотреть на ROOT
Re: Может ли объект "узнать" где он создается?
От: dev_proxy_stub Верблюд да, есть.
Дата: 28.02.12 11:24
Оценка: 1 (1)
Здравствуйте, niralex, Вы писали:


N>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):

N>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме

Чем мешает/неудобен конструктор с параметром ?
----
Re[6]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 28.02.12 20:38
Оценка:
Здравствуйте, enji, Вы писали:

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


NB>>>здесь
Автор: enji
Дата: 20.02.12

N>>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.

E>Ну и что? Идея точно такая-же — из this свойства и имени класса-контейнера получаете указатель на класс-контейнер, и вызываете метод registerProperty()


Там, например, не нравится то, что используется offsetof. Может это и предубеждение, но не хочется использовать решение, когда есть какие-то сомнения.
Re[10]: Рефлексия для бедных...
От: niralex  
Дата: 28.02.12 20:48
Оценка:
Здравствуйте, enji, Вы писали:

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


E>>>Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.


N>>Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код, и пугают, конечно, макросы (почему-то всегда старался их избегать). В любом случае сасибо за внимание к моим проблемам. Честно говоря впечатлен уровнем профессионализма и отзывчивостью лично вашими и других экспертов. Подобного отношения к новичкам не встречал нигде.


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


1. По независящим от меня причинам, студентов(основных пользователей этой системы) учат работать в Embarcadero RAD Studio C++Builder. Перейти на QT самостоятельно в сжатые сроки смогут единицы.
2. По "политическим" мотивам предпочитаем разрабатывать свои велосипеды. Проект не коммерческий, в шею никто не гонит, делаем для себя, почему бы и не попробовать...
Re[8]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 28.02.12 20:50
Оценка:
Здравствуйте, Tonal-, Вы писали:

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

N>>Расскажу о проекте, чтобы требования были лучше понятны и не выглядели надуманными. Система не
N>>коммерческая и используется для научно-исследовательских работ студентов. Например, поставлена
N>>задача для группы студентов: "Использование искусственных нейронных сетей для прогнозирования
N>>временных рядов". Студент должен исследовать разные виды нейронных сетей, алгоритмов обучения,
N>>влияние на результат различных параметров обучающей выборки шаблонов и т.д. У студентов есть
N>>несколько вариантов организации своей работы: воспользоваться матлабом, специализированным ПО
N>>или реализовать все эксперименты самому на С++.
T>Немного не в тему, но наверное тебе будет интересно посмотреть на ROOT

Спасибо за ссылку. Действительно интересно. Если подойдет и воспользуемся, обязательно отпишусь.
Re[2]: Может ли объект "узнать" где он создается?
От: niralex  
Дата: 28.02.12 20:57
Оценка:
Здравствуйте, dev_proxy_stub, Вы писали:

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



N>>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):

N>>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме

__>Чем мешает/неудобен конструктор с параметром ?


Если имеется ввиду, что в качестве параметра конструктора свойства передавать указатель на родителя, то недостаток вижу в том, что это небезопасно. Например, кто-то передаст вместо this указатель на другой компонент... Ошибку можно будет искать очень долго. А учитывая, что множество студентов с разным уровнем подготовки будут писать множество классов, это обязательно когда-нибудь счучится.
Re[3]: Может ли объект "узнать" где он создается?
От: MasterZiv СССР  
Дата: 29.02.12 11:28
Оценка:
> Если имеется ввиду, что в качестве параметра конструктора свойства передавать
> указатель на родителя, то недостаток вижу в том, что это небезопасно. Например,
> кто-то передаст вместо this указатель на другой компонент...

Почему this ? Это that а не this. Ну и тип объекта компилятор в состоянии проверить.
Posted via RSDN NNTP Server 2.1 beta
Re[11]: Рефлексия для бедных...
От: enji  
Дата: 29.02.12 18:25
Оценка:
Здравствуйте, niralex, Вы писали:

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


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

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

в блдере есть собственные свойства и средства для их рантайм-перебора. Кстати, если проект не коммерческий — то каким боком тут рад-студия? она весьма недешевая...
Насчет перехода на qt — не надо на него переходить. Достаточно просто заюзать свойства оттуда, а гуй пишите на чем писали
Re[7]: Может ли объект "узнать" где он создается?
От: enji  
Дата: 29.02.12 18:30
Оценка:
Здравствуйте, niralex, Вы писали:

N>Там, например, не нравится то, что используется offsetof. Может это и предубеждение, но не хочется использовать решение, когда есть какие-то сомнения.


Можно без него, но тогда придется честно хранить указатель, что даст 4 байта на каждое свойство в каждом экземпляре. А то и все 8

Еще можно хранить не указатель, а сдвиг относительно this и надеяться, что он влезет в byte ну или в word
Re[3]: Может ли объект "узнать" где он создается?
От: landerhigh Пират  
Дата: 01.03.12 00:55
Оценка:
Здравствуйте, niralex, Вы писали:


N>Если имеется ввиду, что в качестве параметра конструктора свойства передавать указатель на родителя, то недостаток вижу в том, что это небезопасно. Например, кто-то передаст вместо this указатель на другой компонент...


Вот для этих кого-то и придумали юнит-тесты.
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...
Пока на собственное сообщение не было ответов, его можно удалить.