Написал для своей задачи библиотеку классов. Основной класс-предок и несколько от него потомков. От этих потомков создаются экземпляры и присутствуют в некотором списке, список каждый раз разный.
Каким образом правильно определять какому классу какой экземпляр принадлежит?
Раньше я обходился введением свойства "type" типа const int, в котором хранил номер класса, для каждого свой индивидуальный и не изменяющийся никогда, и чтобы сказать о классе конкретного экземпляра из вышеупомянутого списка, достаточно было это свойство прочитать. Но у Страуструпа говорится, что так делать не комильфо, а как надо рыцца особо некогда. Присоветуйте что-нибудь.
"...Но у Страуструпа говорится, что так делать не комильфо, а, чтобы узнать как надо, рыцца в книжках Страуструпа особо некогда. Присоветуйте что-нибудь."
Здравствуйте, Аноним, Вы писали:
А>Каким образом правильно определять какому классу какой экземпляр принадлежит?
А зачем это выяснять? Хорошо, когда пользователям не важно, какой конкретно там класс...
А>Раньше я обходился введением свойства "type" типа const int, в котором хранил номер класса, для каждого свой индивидуальный и не изменяющийся никогда, и чтобы сказать о классе конкретного экземпляра из вышеупомянутого списка, достаточно было это свойство прочитать. Но у Страуструпа говорится, что так делать не комильфо, а как надо рыцца особо некогда. Присоветуйте что-нибудь.
Ну нехорошо именно писать код так, что клиентскому коду надо знать тип наследника.
Но тип наследника можно узнавать многими способами.
1) при помощи dynamic_cast
2) так, как сделано у тебя
3) В каждом классе иметь статическое поле с описанием, а адрес самого поля использовать, как ID типа
4) Обычно такого рода классы и списки производятся какой-то фабрикой. У фабрики есть шаблон, по которому она создаёт тот или иной экземпляр. Вот экземпляр этого шаблон и можно использовать, как ID...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали:
А>Написал для своей задачи библиотеку классов. Основной класс-предок и несколько от него потомков. От этих потомков создаются экземпляры и присутствуют в некотором списке, список каждый раз разный.
А>Каким образом правильно определять какому классу какой экземпляр принадлежит?
А>Раньше я обходился введением свойства "type" типа const int, в котором хранил номер класса, для каждого свой индивидуальный и не изменяющийся никогда, и чтобы сказать о классе конкретного экземпляра из вышеупомянутого списка, достаточно было это свойство прочитать. Но у Страуструпа говорится, что так делать не комильфо, а как надо рыцца особо некогда. Присоветуйте что-нибудь.
Здравствуйте, ursus_a, Вы писали:
_>"...Но у Страуструпа говорится, что так делать не комильфо, а, чтобы узнать как надо, рыцца в книжках Страуструпа особо некогда. Присоветуйте что-нибудь."
Ты лучше расскажи — зачем тебе знать тип наследника?
B>Ты лучше расскажи — зачем тебе знать тип наследника?
Не мне знать его нужно, а программе определять. Например, чтобы нужный фрейм с полями ввода свойств подставить в зависимости от типа текущего (выделенного указателем) объекта.
Здравствуйте, ursus_a, Вы писали:
B>>Ты лучше расскажи — зачем тебе знать тип наследника?
_>Не мне знать его нужно, а программе определять. Например, чтобы нужный фрейм с полями ввода свойств подставить в зависимости от типа текущего (выделенного указателем) объекта.
Можно использовать виртуальные функции для этого. RTTI в языке со статической типизацией это не всегда хорошо.
E>Ну нехорошо именно писать код так, что клиентскому коду надо знать тип наследника. E>Но тип наследника можно узнавать многими способами. E>1) при помощи dynamic_cast E>2) так, как сделано у тебя E>3) В каждом классе иметь статическое поле с описанием, а адрес самого поля использовать, как ID типа E>4) Обычно такого рода классы и списки производятся какой-то фабрикой. У фабрики есть шаблон, по которому она создаёт тот или иной экземпляр. Вот экземпляр этого шаблон и можно использовать, как ID...
ну, может и нехорошо, но если я буду писать про всю задачу, то стока букаф никто ни асилит. А за советы спасибо.
Если интересно, то вкратце. Есть кучка (список) соединенных четырехполюсников, около 15, каждый своего типа, типов примерно пять. У каждого типа свой набор свойств. Эти свойства надо вводить в экранных формах. На экране отображается список ЧП и набор свойств одного из них. Мне надо сделать так, что когда я выбираю конкретный ЧП из списка курсором,определялся тип объекта, и в соответствии с ним выдавалась форма для ввода свойств.
Пока писал, сообразил, как это можно сделать еще, но сначала таки-сделаю по своему.
Здравствуйте, ursus_a, Вы писали:
_>Если интересно, то вкратце. Есть кучка (список) соединенных четырехполюсников, около 15, каждый своего типа, типов примерно пять. У каждого типа свой набор свойств. Эти свойства надо вводить в экранных формах. На экране отображается список ЧП и набор свойств одного из них. Мне надо сделать так, что когда я выбираю конкретный ЧП из списка курсором,определялся тип объекта, и в соответствии с ним выдавалась форма для ввода свойств.
_>Пока писал, сообразил, как это можно сделать еще, но сначала таки-сделаю по своему.
Псевдокод:
class BaseQuadripole
{
public:
virtual void printInfo(InfoPrinter &) const = 0;
virtual ~BaseQuadripole() {}
};
class QuadripoleType1
: public BaseQuadripole
{
public:
void printInfo(InfoPrinter & ip) const
{
ip << option1 << option2;
}
private:
// свойства
// option1, option2
};
class QuadripoleType2
: public BaseQuadripole
{
public:
void printInfo(InfoPrinter & ip) const
{
ip << option1 << option2 << option3;
}
private:
// свойства
// option1, option2, option3
};
int main()
{
InfoPrinter pr;
BaseQuadripole * qp = getPointerFromCursor();
qp->printInfo(pr);
}
Здравствуйте, ursus_a, Вы писали:
_>Если интересно, то вкратце. Есть кучка (список) соединенных четырехполюсников, около 15, каждый своего типа, типов примерно пять. У каждого типа свой набор свойств. Эти свойства надо вводить в экранных формах. На экране отображается список ЧП и набор свойств одного из них. Мне надо сделать так, что когда я выбираю конкретный ЧП из списка курсором,определялся тип объекта, и в соответствии с ним выдавалась форма для ввода свойств.
может ЧП при создании рассказать, какая форма ему нужна?.
но вообще id типа не означает id класса, это у тебя так сложилось.. частный случай.. классов может быть больше для одного и того же типа.. поэтому я бы, наверное, оставил type_id..
Здравствуйте, ursus_a, Вы писали:
_>Если интересно, то вкратце. Есть кучка (список) соединенных четырехполюсников, около 15, каждый своего типа, типов примерно пять. У каждого типа свой набор свойств. Эти свойства надо вводить в экранных формах. На экране отображается список ЧП и набор свойств одного из них. Мне надо сделать так, что когда я выбираю конкретный ЧП из списка курсором,определялся тип объекта, и в соответствии с ним выдавалась форма для ввода свойств.
, но если не хочется смешивать представление класса и сам класс, можно разделить на несколько классов:
// Отображатель полей ввода на форме (предопределение):class FormProperties;
// Базовый класс для четырёхполюсников:template<class T>
class BaseQuadripole {
public:
// Загрузка свойств на форму:void load ( FormProperties const& properties ) const;
// Если нужно - сохранение свойств при закрытии формы:void save ( FormProperties& properties );
// Определение двух верхних ф-ций - после определения класса FormProperties.
};
class SomeQuadripole : public BaseQuadripole<SomeQuadripole> {
public:
// Конструкторы, методы доступа, свойства...
};
class AnotherQuadripole : public BaseQuadripole<AnotherQuadripole> {
public:
// Конструкторы, методы доступа, свойства...
};
// Можно разбить на базовый и производные классы, если предполагается несколько отображений:class FormProperties {
public:
// Конструкторы и всё такое.void load ( SomeQuadripole const& quadripole ) const {
// здесь создаём поля ввода для данного типа четырёхполюсника
}
void save ( SomeQuadripole& quadripole ) {
// А здесь сохраняем из поля ввода новое состояние для четырёхполюсника данного типа
}
// Аналогично:void load ( AnotherQuadripole const& quadripole ) const { /* ... */ }
void save ( AnotherQuadripole& quadripole ) { /* ... */ }
};
// Двойная диспетчеризация:template<class T>
void BaseQuadripole<T>::load ( FormProperties const& properties ) const {
properties.load ( static_cast<T const&> ( *this ) );
}
template<class T>
void BaseQuadripole<T>::save ( FormProperties& properties ) {
properties.save ( static_cast<T&> ( *this ) );
}
Здравствуйте, ursus_a, Вы писали:
_>Пока писал, сообразил, как это можно сделать еще, но сначала таки-сделаю по своему.
Ну это стандартная же задача. Обычно идут по одному из двух путей.
Путь 1. У базы ЧП есть виртуальный метод ShowProperties. Соответсвенно оно всё и делает.
Путь 2. Если в программе интерфейс отделён от бизнес-логики, то можно, например, иметь в программе специальные структуры данных, назовём их шаблонами четырёхполюсников. Шаблон содержит в себе информацию о том, какого именно типа сам ЧП, какого типа вьюшка его свойств и т. д.
Ну и по этому шаблону всё и создаём, при нужде. При этом ЧП может хранить в себе указатель на создавший его шаблон.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ursus_a, Вы писали:
M>>Если необходимо достучаться до конкретного потомка, тогда архитектура кривовата.
_>Потомка... класса? Или экземпляра?
Я не понял вас, на примере можете показать, что вы имели в виду ?
Cпасибо всем огромное, особенно за RTTI и за потоки. Забыл одно важное уточнение: библиотека должна компилироваться "и в окопе, и в траншее", то есть и для ПК, и для сигнального процессора, поэтому многие удобные штуки, характерные для ПК тут не прокатывают.
В таком случае не зазорно и просто самому вручную ставить свойство класса-константу, которая будет обозначать тип класса, хватит и переменной типа int. А можно еще с каждого класса собирать какое-нибудь характерное только для него (для каждого экземпляра) число. Например, указатель на конструктор этого класса. и по этому указателю идентифицировать, к какому классу принадлежит экземпляр.
Вопрос не столько в работоспособности, сколько в корректности идеи: насколько это приемлемо?
Здравствуйте, ursus_a, Вы писали:
_>Например, указатель на конструктор этого класса. и по этому указателю идентифицировать, к какому классу принадлежит экземпляр.
IMHO, тогда уж намного лучше заиметь статическое поле с описанием каких-то данных про каждый конкретный класс. Например его имя можно там хранить, список атрибутов, ещё что-нибудь.
Заполнять всё это можно макросом, кстати.
_>Вопрос не столько в работоспособности, сколько в корректности идеи: насколько это приемлемо? _>Хотя проще, конечно, циферку поставить =).
У циферки есть та проблема, что расширять набор типов неудобно.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ursus_a, Вы писали:
M>>Если необходимо достучаться до конкретного потомка, тогда архитектура кривовата.
_>Потомка... класса? Или экземпляра?
Достучаться до экземпляра потомка через экземпляр предка. Речь идет о рантайме.
Здравствуйте, ursus_a, Вы писали:
_>... А можно еще с каждого класса собирать какое-нибудь характерное только для него (для каждого экземпляра) число. Например, указатель на конструктор этого класса.
На всякий случай:
12.1/1
Constructors do not have names.
...
12.1/12
...
The address of a constructor shall not be taken.