Извините, если мой вопрос такой длинный и технический, но я думаю, что это так важно, что другие люди заинтересуются этим
Я искал способ четко отделить некоторые компоненты программного обеспечения от их представления в c ++
У меня есть универсальный класс параметров (который будет позже сохранен в контейнере), который может содержать любое значение с помощью boost :: any class
У меня есть базовый класс (примерно) такого рода (конечно, есть еще вещи)
class Parameter
{
public:
Parameter()
template typename<T> T GetValue() const { return any_cast<T>( _value ); }
template typename<T> void SetValue(const T& value) { _value = value; }
string GetValueAsString() const = 0;
void SetValueFromString(const string& str) const = 0;
private:
boost::any _value;
}
Существует два уровня производных классов:
Первый уровень определяет тип и преобразование в / из строки (например, ParameterInt или ParameterString)
Второй уровень определяет поведение и реальных создателей (например, получение ParameterAnyInt и ParameterLimitedInt из ParameterInt или ParameterFilename из GenericString)
В зависимости от реального типа я хотел бы добавить внешнюю функцию или классы, которые работают в зависимости от конкретного типа параметра, без добавления виртуальных методов в базовый класс и без выполнения странных приведений
Например, я хотел бы создать соответствующие элементы управления графическим интерфейсом в зависимости от типов параметров:
Widget* CreateWidget(const Parameter& p)
Конечно, я не могу понять настоящий тип параметра из этого, если я не использую RTTI или не использую его самостоятельно (с перечислением и регистром переключателя), но это не правильное проектное решение ООП, вы знаете.
Классическим решением является шаблон проектирования Visitor http://en.wikipedia.org/wiki/Visitor_pattern
Проблема с этим шаблоном заключается в том, что мне нужно заранее знать, какие производные типы будут реализованы, поэтому (собрав воедино то, что написано в Википедии и моем коде), у нас будет что-то вроде:
struct Visitor
{
virtual void visit(ParameterLimitedInt& wheel) = 0;
virtual void visit(ParameterAnyInt& engine) = 0;
virtual void visit(ParameterFilename& body) = 0;
};
Есть ли какое-либо решение для получения такого поведения любым другим способом без необходимости заранее знать все конкретные типы и без извлечения первоначального посетителя?
Редактировать: Д-р. Решение Pizza кажется наиболее близким к тому, о чем я думал , но проблема все та же, и метод фактически полагается на dynamic_cast, которого я пытался избежать как своего рода (даже если слабый) метод RTTI
Может быть, лучше подумать над каким-нибудь решением, даже не упомянув Шаблон посетителя, и очистить наш разум. Цель просто иметь такую функцию:
Widget* CreateWidget(const Parameter& p)
ведет себя по-разному для каждого "конкретного" параметра, не теряя информацию о его типе