Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):
class B;
class A
{
public:
A()
{
/* здесь нужно получать указатель на родительский объект или NULL, если объект создается глобально*/
}
};
class B
{
public:
A a1;
};
Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме.
N>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):
Полагаю, что никак. Более того, к моменту вызова конструктора внутреннего класса внешний еще не создан — и смысла в этом указателе в практическом плане я не вижу.
N>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции): N>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме.
Здравствуйте, MasterZiv, Вы писали:
MZ>Нельзя.
MZ>Решение простое -- сделай соотв. конструктор, вызывай его в "родителе", MZ>передавай "ребёнку" ссылку на "родителя".
это решение понятно, но я искал решение без передачи параметра в конструктор.
> MZ>Решение простое -- сделай соотв. конструктор, вызывай его в "родителе", > MZ>передавай "ребёнку" ссылку на "родителя". > > это решение понятно, но я искал решение без передачи параметра в конструктор.
Тебе же сказали, в рамках языка С++ нет. можешь искать дальше, конечно, дело твоё.
Здравствуйте, Константин, Вы писали:
К>Интересно, а что за задача решается?
Попробую объяснить задачу без значительных упрощений.
Требуется разработать базовый класс иерархии, который бы обеспечивал обобщенный унифицированный интерфейс доступа ко всем объектам иерархии. При этом количество классов велико, классы разрабатываются разными людьми для разных задач. Под доступом понимается возможность обращаться к членам классов для чтения/изменения значений. Другими словами, каждый класс должен иметь два интерфейса, один из котороых обощенный, чтобы со всеми объектами можно было работать однотипно.
В одном из решений задачи, которое используется в данный момент, все классы рассмотриваются как контейнеры специальных объектов-свойств, которые в общем случае являются простыми оболочками для стандартных типов.
Это выглядит примерно так:
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. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?
Здравствуйте, niralex, Вы писали:
N>Возникла идея, чтобы конструкторы классов свойств сами себя добавляли в контейнер _props. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, niralex, Вы писали:
N>>Возникла идея, чтобы конструкторы классов свойств сами себя добавляли в контейнер _props. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?
NB>здесь
Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.
Здравствуйте, niralex, Вы писали:
N>Требуется разработать базовый класс иерархии, который бы обеспечивал обобщенный унифицированный интерфейс доступа ко всем объектам иерархии. При этом количество классов велико, классы разрабатываются разными людьми для разных задач. Под доступом понимается возможность обращаться к членам классов для чтения/изменения значений. Другими словами, каждый класс должен иметь два интерфейса, один из котороых обощенный, чтобы со всеми объектами можно было работать однотипно.
N>В одном из решений задачи, которое используется в данный момент, все классы рассмотриваются как контейнеры специальных объектов-свойств, которые в общем случае являются простыми оболочками для стандартных типов.
А нужно иметь возможность создавать одинокие свойства? Которые не лежат в контейнере?
А то можно же просто добавить в конструктор свойства BaseComponent*, и всё сразу заиграет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, niralex, Вы писали:
N>>>Возникла идея, чтобы конструкторы классов свойств сами себя добавляли в контейнер _props. Благо, иерархия классов свойств относительно небольшая и устоявшаяся. Для этого и понадобилось узнать где объект-свойство создается. Имея указатель на родительский объект, свойство смогло бы само себя добавить в конструкторе. Но, пока не знаю как это реализовать. Возможно, кто-нибудь подскажет другие идеи?
NB>>здесь
N>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.
то есть, как реализована там передача информации о родителе ты посмотрел?
21.02.12 19:01, niralex написав(ла): > Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции):
[perversion mode on]
Контейнер наследуется от базового класса, который сохраняет ссылку на
себя в глобальной переменной. Компонента проверяет эту ссылку в
конструкторе и сбрасывает её.
Разумеется, есть множество случаев, когда это «работать» не будет.
[perversion mode off]
N>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме. C чем связано требование про без параметров? Если требование не строгое, а нужно, чтобы объект просто вел себя как будто у него есть конструктор без параметров, то можно передавать туда значения по умолчанию. Типа такого
//какая фигня описывающая контекст
struct Context
{
int a;
};
//получение контекста, вся логика обработки именно в этой функции
Context* getGlobalContext()
{
return NULL;
}
//многострадальная пропертя
struct PropertyType
{
PropertyType(Context* c = getGlobalContext())
{
;
}
~PropertyType()
{
;
}
int b;
};
Здравствуйте, denisko, Вы писали:
D>Здравствуйте, niralex, Вы писали:
N>>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме. C чем связано требование про без параметров? Если требование не строгое, а нужно, чтобы объект просто вел себя как будто у него есть конструктор без параметров, то можно передавать туда значения по умолчанию. Типа такого
Кстати подумал, есть еще грязный способ через переопределение unexpected (тогда и никаких параметров не надо передавать вообще), но он, работает только в теории, и слава богу.
Здравствуйте, Erop, Вы писали:
E>А нужно иметь возможность создавать одинокие свойства? Которые не лежат в контейнере? E>А то можно же просто добавить в конструктор свойства BaseComponent*, и всё сразу заиграет...
Одинокие свойства не нужны. Считается, что они неотделимы от компонента.
Если я правильно понял мысль, то конструкторы свойств должны быть такими:
а компонент будет обязан передавать this при создании свойства.
Такой вариант рассматривается, он всем хорош, но пугает небольшая проблема — вдруг кто-то передаст вместо this, указатель на какой-нибудь другой компонент...
N>>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.
NB>то есть, как реализована там передача информации о родителе ты посмотрел?
нет, глубоко не вник, при поверхностном рассмотрении показалось что не то, извиняюсь.
Сейчас пытаюсь разобраться, но сложновато для моего уровня...
Здравствуйте, gegMOPO4, Вы писали:
MOP>[perversion mode on] MOP>Контейнер наследуется от базового класса, который сохраняет ссылку на MOP>себя в глобальной переменной. Компонента проверяет эту ссылку в MOP>конструкторе и сбрасывает её.
MOP>Разумеется, есть множество случаев, когда это «работать» не будет. MOP>[perversion mode off]
Согласен, это решает и тоже рассматривается как вариант. Я даже писал рабочий набросок кода который все это реализует, правда немного усовершенствованный — для создания компонента используется глобальная функция, которая сбрасывает глобальный указатель, чтобы это не "забывали" делать компоннеты. Но в этом варианте не нравится использование глобальной переменной. Например, как быть, если в компоненте создается вложенный компонент(хотя это можно попробовать решить через стек глобальных указателей на компоненты, которые создаются в данный момент) или что будет в многопоточном приложении, где каждый объект содает свои компоненты? В целом, чувствую, что как-то это все не так...
N>>>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.
NB>>то есть, как реализована там передача информации о родителе ты посмотрел?
N>нет, глубоко не вник, при поверхностном рассмотрении показалось что не то, извиняюсь. N>Сейчас пытаюсь разобраться, но сложновато для моего уровня...
если в двух словах, то для каждого свойства генерируется свой класс вида:
Здравствуйте, niralex, Вы писали:
N>Такой вариант рассматривается, он всем хорош, но пугает небольшая проблема — вдруг кто-то передаст вместо this, указатель на какой-нибудь другой компонент...
типа свойства вообще всегда хрянятся внутри базы, а в нследниках если надо, запонимают ссылки на нужные переменные.
Кстати, при таком подходе, я бы ещё и имена у пропертей поубирал, зачем они им? По идее, имя должно знасть множество.
А у вас множественное наследование бывает?
На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип, а не на экземпляр...
Так и быстрее и веселее должно быть.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали: E>А у вас множественное наследование бывает?
Нет, даже композиции нет. Концепция такая — компоненты состоят только из свойств,
действий(объекты-оболочки для указателей на функции-члены) и
ссылок(объекты-указатели на другие компоненты, включающие информацию о типе на который должны
указывать). Причем, классы компонентов помещаются в динамические библиотеки. Есть главная
программа, в которой можно подгрузить библиотеки, создать необходимые компоненты, настроить
связи между ними, просмотреть/изменить значения свойств, выполнить действия для компонентов,
сохранить/открыть компоненты.
Расскажу о проекте, чтобы требования были лучше понятны и не выглядели надуманными. Система не
коммерческая и используется для научно-исследовательских работ студентов. Например, поставлена
задача для группы студентов: "Использование искусственных нейронных сетей для прогнозирования
временных рядов". Студент должен исследовать разные виды нейронных сетей, алгоритмов обучения,
влияние на результат различных параметров обучающей выборки шаблонов и т.д. У студентов есть
несколько вариантов организации своей работы: воспользоваться матлабом, специализированным ПО
или реализовать все эксперименты самому на С++. По ряду причин последний вариант наиболее
эффективный при условии хорошего владения средствами языка. Вот в этом и проблема. Группе
студентов тяжело все разработать и запрограммировать "с нуля" в условиях постоянно меняющихся
требований(постоянно появляются новые идеи), отсутвия должных навыков групповой работы, да и
вообще опыта разработки ПО. Для решения этих проблем и была разработана описываемая система.
Теперь так — студентам дается образец кода одного из компонентов и
поясняются несложные правила написания компонентов(от какого класса наследовать, как определять
свойства, связи и действия), а также готовая главная программа. Каждому дается своя задача на
разработку компонента(ов), например кто-то делает компонент NuralNetwork, кто-кто
GeneticAlgorihtm, кто-то Crossover, кто-то Patterns и т.д. Затем в основной прогармме это все
связывается и запускается. Если появилась идея, типа "а давайте попробуем полносвязную нейронную
сеть...", деаем еще один компонент, меняем одну связь в главной программе и смотрим на
результат. Кроме этого есть уже готовые компоненты, написанные "предыдущими покаолениями"
студентов. Когда получаем приемлемый результат исследований, то компонент может быть легко заюзан в отдельном
демонстрационном или рабочем приложении. Главное что мы получили — четкое разделение, повторное
использование кода и скорость реализации идей. Текущая проблема с системой — большое количество
глюков в компонентах из-за непрофессионализма разработчиков. Насущная задача — доработка системы
таким образом, чтобы студентам было как можно проще создавать компоненты и оставалось как можно
меньше возможностей для ошибок, а те что все же допущены можно бы было лекго обнаруживать при
общем тестировании компонента до того, как он будет использоваться.
E>На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип,
а не на экземпляр... E>Так и быстрее и веселее должно быть.
Согласен, но как это красиво реализовать. Ведь такие параметры свойств, как имя, атрибут "только
для чтения" и другое относятся к типу, а значение свойства — у каждого объекта свое.
On 02/23/2012 01:19 PM, niralex wrote:
> Нет, даже композиции нет. Концепция такая — компоненты состоят только из свойств, > действий(объекты-оболочки для указателей на функции-члены) и > ссылок(объекты-указатели на другие компоненты, включающие информацию о типе на > который должны > указывать).
По-моему простой список свойств тут подошёл бы лучше.
Плюс возможно объект-flyweigh для реализации логики работы с этими свойствами.
Хочу заметить, что согласно стандарту (в новом это 18.2.4) макрос offsetof применим только к standard-layout class и поэтому (IMHO) данный прием niralex'у не подходит.
Здравствуйте, MasterZiv, Вы писали:
MZ>On 02/23/2012 01:19 PM, niralex wrote:
>> Нет, даже композиции нет. Концепция такая — компоненты состоят только из свойств, >> действий(объекты-оболочки для указателей на функции-члены) и >> ссылок(объекты-указатели на другие компоненты, включающие информацию о типе на >> который должны >> указывать).
MZ>По-моему простой список свойств тут подошёл бы лучше. MZ>Плюс возможно объект-flyweigh для реализации логики работы с этими свойствами.
не понял идею, можно подробнее. Что такое паттерн flyweigh представление имею.
> MZ>По-моему простой список свойств тут подошёл бы лучше. > MZ>Плюс возможно объект-flyweigh для реализации логики работы с этими свойствами. > > не понял идею, можно подробнее. Что такое паттерн flyweigh представление имею. > Re[8]: Может ли объект "узнать" где он создается? <message/4631013.aspx>
Здравствуйте, niralex, Вы писали:
E>>На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип, N>а не на экземпляр... E>>Так и быстрее и веселее должно быть.
N>Согласен, но как это красиво реализовать. Ведь такие параметры свойств, как имя, атрибут "только N>для чтения" и другое относятся к типу, а значение свойства — у каждого объекта свое.
Ну, на мой взгляд, тут бы надо что-то в консерватории подправить. Например пересадить студней не какой-то язык с строенной поддержкой всех этих дел. На дельфи там, или на шарп...
Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.
Только я немного переформулирую твою задачу, чтобы немного отстраниться от ваших дел.
Мы, типа, хотим писать какие-то классы, просто так брать и писать, а потом некоторые из полей этих классов делать доступными через интерфейс, который эти классы поддерживают. На поля мы хотим ссылаться по именам.
И мы хотим, чтобы публикация проходила декларативно, а работало всё это безопасно.
Первое, что нам понадобится -- это способ как-то сослаться на данные неизвестного типа. Это должно быть копируемое данное, которое можно вернуть из функции и потом у него расспросить, что за тип там внутри, прочитать, записать и т. д.
Есть много разных библиотек, которые решают эту задачу по всякому, так что я не буду заострять внимание на этом всём подробно. Просто напишу какой-то DataRef для бедных. А для реальных задач уже можно будет сделать хорошо, или взять библиотечный.
Итак, к вашим услугам относительно безопасный void* :
У меня, на том же компиляторе, 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;
}
Обрати внимание на строку // !!!
Мы там создаём временный объект — наследник, и продлеваем ему время жизни при помощи статической сонстантной ссылки на базу. Это позволяет нам не указывать при регистрации поля его тип, а выводить его...
Собсвтенно вот.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, niralex, Вы писали:
E>>>На самом деле в этой всей системе есть один косяк. Свойства, по идее, можно бы регить на тип, N>>а не на экземпляр... E>>>Так и быстрее и веселее должно быть.
N>>Согласен, но как это красиво реализовать. Ведь такие параметры свойств, как имя, атрибут "только N>>для чтения" и другое относятся к типу, а значение свойства — у каждого объекта свое.
E>Ну, на мой взгляд, тут бы надо что-то в консерватории подправить. Например пересадить студней не какой-то язык с строенной поддержкой всех этих дел. На дельфи там, или на шарп...
"Встроенная" поддержка не всегда подходит... или мы не до конца с ней раобрались
E>Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.
Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код, и пугают, конечно, макросы (почему-то всегда старался их избегать). В любом случае сасибо за внимание к моим проблемам. Честно говоря впечатлен уровнем профессионализма и отзывчивостью лично вашими и других экспертов. Подобного отношения к новичкам не встречал нигде.
Здравствуйте, niralex, Вы писали:
N>Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код,
Можно как-то поменять DataRef, тем более, что DataRef достаточно на коленке написана тут.
Ну и, нсколько я понял, у вас всё время пишутся новые компоненты
N>и пугают, конечно, макросы (почему-то всегда старался их избегать).
Ну это да. И правильно старался (тут принято на "ты" обращаться к коллегам).
Но тут на компромисс некий приходится идти, так как при таком подходе сложнее допустить ошибку.
Правда там у меня есть ошибка в макросе. В FIELD_MAPPING_BEGIN( THE_CLASS ) вместо typedef TestClass TheClass_; должно быть typedef THE_CLASS TheClass_; \
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
N>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.
Ну и что? Идея точно такая-же — из this свойства и имени класса-контейнера получаете указатель на класс-контейнер, и вызываете метод registerProperty()
Здравствуйте, niralex, Вы писали:
E>>Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.
N>Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код, и пугают, конечно, макросы (почему-то всегда старался их избегать). В любом случае сасибо за внимание к моим проблемам. Честно говоря впечатлен уровнем профессионализма и отзывчивостью лично вашими и других экспертов. Подобного отношения к новичкам не встречал нигде.
Кстати, а чего вы тот-же Qt не заюзаете? Свойства там есть и как раз такие, как вам нужны. Плюс поддержка от ИДЕ и очень хороший хелп
Здравствуйте, niralex, Вы писали: N>Расскажу о проекте, чтобы требования были лучше понятны и не выглядели надуманными. Система не N>коммерческая и используется для научно-исследовательских работ студентов. Например, поставлена N>задача для группы студентов: "Использование искусственных нейронных сетей для прогнозирования N>временных рядов". Студент должен исследовать разные виды нейронных сетей, алгоритмов обучения, N>влияние на результат различных параметров обучающей выборки шаблонов и т.д. У студентов есть N>несколько вариантов организации своей работы: воспользоваться матлабом, специализированным ПО N>или реализовать все эксперименты самому на С++.
Немного не в тему, но наверное тебе будет интересно посмотреть на ROOT
N>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции): N>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме
N>>Спасибо, идея хорошая, но немного не то что надо. В контексте моей задачи концепция свойств другая(возможно, просто я неудачное название выбрал). В данном случае свойства не обязательно должны маскироваться под переменную, а просто обеспечивать доступ к переменным обобщенным способом.
E>Ну и что? Идея точно такая-же — из this свойства и имени класса-контейнера получаете указатель на класс-контейнер, и вызываете метод registerProperty()
Там, например, не нравится то, что используется offsetof. Может это и предубеждение, но не хочется использовать решение, когда есть какие-то сомнения.
Здравствуйте, enji, Вы писали:
E>Здравствуйте, niralex, Вы писали:
E>>>Но если вам С++ милее всего, то можно примерно всё тоже самое замутить и на нём, конечно же.
N>>Да, вариант похоже решает задачу, но мне еще нужно до конца с ним разобраться, прикинуть насколько сложно будет переписать существующий код, и пугают, конечно, макросы (почему-то всегда старался их избегать). В любом случае сасибо за внимание к моим проблемам. Честно говоря впечатлен уровнем профессионализма и отзывчивостью лично вашими и других экспертов. Подобного отношения к новичкам не встречал нигде.
E>Кстати, а чего вы тот-же Qt не заюзаете? Свойства там есть и как раз такие, как вам нужны. Плюс поддержка от ИДЕ и очень хороший хелп
1. По независящим от меня причинам, студентов(основных пользователей этой системы) учат работать в Embarcadero RAD Studio C++Builder. Перейти на QT самостоятельно в сжатые сроки смогут единицы.
2. По "политическим" мотивам предпочитаем разрабатывать свои велосипеды. Проект не коммерческий, в шею никто не гонит, делаем для себя, почему бы и не попробовать...
Здравствуйте, Tonal-, Вы писали:
T>Здравствуйте, niralex, Вы писали: N>>Расскажу о проекте, чтобы требования были лучше понятны и не выглядели надуманными. Система не N>>коммерческая и используется для научно-исследовательских работ студентов. Например, поставлена N>>задача для группы студентов: "Использование искусственных нейронных сетей для прогнозирования N>>временных рядов". Студент должен исследовать разные виды нейронных сетей, алгоритмов обучения, N>>влияние на результат различных параметров обучающей выборки шаблонов и т.д. У студентов есть N>>несколько вариантов организации своей работы: воспользоваться матлабом, специализированным ПО N>>или реализовать все эксперименты самому на С++. T>Немного не в тему, но наверное тебе будет интересно посмотреть на ROOT
Спасибо за ссылку. Действительно интересно. Если подойдет и воспользуемся, обязательно отпишусь.
Здравствуйте, dev_proxy_stub, Вы писали:
__>Здравствуйте, niralex, Вы писали:
N>>Можно ли в конструкторе объекта без параметров каким-либо образом получить указатель на объект в котором он создается (в случае композиции): N>>Буду очень благодарен за любые решения, идеи или ссылки на материалы, где можно почитать по теме
__>Чем мешает/неудобен конструктор с параметром ?
Если имеется ввиду, что в качестве параметра конструктора свойства передавать указатель на родителя, то недостаток вижу в том, что это небезопасно. Например, кто-то передаст вместо this указатель на другой компонент... Ошибку можно будет искать очень долго. А учитывая, что множество студентов с разным уровнем подготовки будут писать множество классов, это обязательно когда-нибудь счучится.
> Если имеется ввиду, что в качестве параметра конструктора свойства передавать > указатель на родителя, то недостаток вижу в том, что это небезопасно. Например, > кто-то передаст вместо this указатель на другой компонент...
Почему this ? Это that а не this. Ну и тип объекта компилятор в состоянии проверить.
Здравствуйте, niralex, Вы писали:
E>>Кстати, а чего вы тот-же Qt не заюзаете? Свойства там есть и как раз такие, как вам нужны. Плюс поддержка от ИДЕ и очень хороший хелп
N>1. По независящим от меня причинам, студентов(основных пользователей этой системы) учат работать в Embarcadero RAD Studio C++Builder. Перейти на QT самостоятельно в сжатые сроки смогут единицы. N>2. По "политическим" мотивам предпочитаем разрабатывать свои велосипеды. Проект не коммерческий, в шею никто не гонит, делаем для себя, почему бы и не попробовать...
в блдере есть собственные свойства и средства для их рантайм-перебора. Кстати, если проект не коммерческий — то каким боком тут рад-студия? она весьма недешевая...
Насчет перехода на qt — не надо на него переходить. Достаточно просто заюзать свойства оттуда, а гуй пишите на чем писали
Здравствуйте, niralex, Вы писали:
N>Там, например, не нравится то, что используется offsetof. Может это и предубеждение, но не хочется использовать решение, когда есть какие-то сомнения.
Можно без него, но тогда придется честно хранить указатель, что даст 4 байта на каждое свойство в каждом экземпляре. А то и все 8
Еще можно хранить не указатель, а сдвиг относительно this и надеяться, что он влезет в byte ну или в word
N>Если имеется ввиду, что в качестве параметра конструктора свойства передавать указатель на родителя, то недостаток вижу в том, что это небезопасно. Например, кто-то передаст вместо this указатель на другой компонент...
Здравствуйте, enji, Вы писали:
E>Здравствуйте, niralex, Вы писали:
E>>>Кстати, а чего вы тот-же Qt не заюзаете? Свойства там есть и как раз такие, как вам нужны. Плюс поддержка от ИДЕ и очень хороший хелп
N>>1. По независящим от меня причинам, студентов(основных пользователей этой системы) учат работать в Embarcadero RAD Studio C++Builder. Перейти на QT самостоятельно в сжатые сроки смогут единицы. N>>2. По "политическим" мотивам предпочитаем разрабатывать свои велосипеды. Проект не коммерческий, в шею никто не гонит, делаем для себя, почему бы и не попробовать...
E>в блдере есть собственные свойства и средства для их рантайм-перебора.
да, но поддержка этих свойств(если имеется ввиду __property) за счет нестандартных средств компилятора и во-вторых слишком громоздко получается.
Е>Кстати, если проект не коммерческий — то каким боком тут рад-студия? она весьма недешевая...
а никто и не покупает... проект для внутреннего использования.
E>Насчет перехода на qt — не надо на него переходить. Достаточно просто заюзать свойства оттуда, а гуй пишите на чем писали
я, конечно, глубоко не вникал в qt, но думаю не так просто вычленить оттуда систему поддержки свойств, во всяком случае для нас.
После долгих и мучительных размышлений решил остановиться на таком варианте решения своей задачи, которую лучше всего сформулировал 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-а(спасибо, оказались очень полезными)
и старый топик о конструкторах класса
В связи с недостаточностью моих знаний и практики в области С++, многие из предложенных другими участниками решений не подошли по банальной причине — не смог их понять
Приведенное решение не окончательное. Если кто-то видит потенциальные проблемы, ошибки и т.д., буду рад услышать об этом.
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.
Здравствуйте, Анатолий Широков, Вы писали:
N>>Приведенное решение не окончательное. Если кто-то видит потенциальные проблемы, ошибки и т.д., буду рад услышать об этом.
АШ>А зачем же так многословно-то? тынц
В твоем решении я вижу две проблемы:
1) имена полей не статические, т.е. каждый объект класса будет хранить свою копию std::map<std::string, boost::any> property; Это, как минимум нерационально.
2) Например, есть уже написанный класс и нужно сделать из него компонент, т.е. сделать свойства из уже существующих полей. В моем решении я только добавлю наследование от TComIniter<Type> и макросы BEGIN...END. Все. При этом размер объектов не увеличится. В твоем случае будет сложнее... Хочется, чтобы класс можно было писать не думая о том, что там будут какие-то свойства, а потом просто дополнить чем-то по-минимуму, чтобы появились свойства.
Здравствуйте, 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 и есть предубеждение, что использование подобных штук(если они имелись в виду) скажется на размере/производительности/удобстве использования. Или я не прав?
N>Да, в целом согласен. В оправдание могу только сказать, что это все это спрятано "внутри", т.е. клиентский код не работает с viod* напрямую, а использует медод PropertyAs<Type>(string), куда можно добавить всякие проверки, assert-ы и т.д и пполучить свой велосипед. Во вторых, в моем проекте есть своя специфика — все пользовательские классы помещаются в dll-ки, для чего классы "заворачиваются" в С-оболочку(понимаю, что звучит дико). Там естественно используется void*, что красиво стыкуется с приведенным кодом. Ну и главное — я не работал никогда с boost::any или boost::variant и есть предубеждение, что использование подобных штук(если они имелись в виду) скажется на размере/производительности/удобстве использования. Или я не прав?
В общем случае, при выборе средств "предубеждение" должно быть последним на чаша весов "за" или "против". А так, как и в любой исследовательской работе, сначала изучаешь, что уже есть, выделяешь достоинства и недостатки, проводишь эксперименты с целью выявить осязаемые метрики, дабы при сравнении оперировать конкретными "цифирями". Это все общие слова, конечно. В своих проектах отдавал и отдаю предпочтение средствам стандартным и хорошо специфицированным.
> красиво стыкуется с приведенным кодом. Ну и главное — я не работал никогда с > boost::any или boost::variant и есть предубеждение, что использование подобных > штук(если они имелись в виду)
Я имел в виду не их, что-то типа свойств на шаблонах.
скажется на размере/производительности/удобстве
На удобстве конечно скажется. А на размер и производительность, думаю, тебе
обращать внимание не нужно.