Одной из прелестей C ++ является то, что такого рода навязчивые решения часто не нужны, но, к сожалению, мы до сих пор видим, как подобные решения реализуются сегодня.Вероятно, это связано с преобладанием Java, .NET и QT, которое следует за этими типами моделей, где у нас есть общий базовый класс объектов, который наследуется почти всем.
Под навязчивым подразумевается то, чтоиспользуемые типы должны быть изменены для работы с агрегатной системой (в данном случае наследуя от базового объекта).Одна из проблем с навязчивыми решениями (хотя иногда и уместными) заключается в том, что они требуют объединения этих типов с системой, используемой для их агрегирования: типы становятся зависимыми от системы.Для POD невозможно использовать навязчивые решения напрямую, так как мы не можем изменить интерфейс int, например: становится необходимым использование оболочки.Это также верно для типов вне вашего контроля, таких как стандартная библиотека C ++ или boost.В результате вы тратите много времени и усилий на создание оболочек для всех видов вещей, когда такие оболочки легко можно было бы создать в C ++.Это также может быть очень пессимистично для вашего кода, если навязчивое решение применяется единообразно даже в тех случаях, когда это не нужно и требует затрат времени выполнения / памяти.
С C ++, множество неинтрузивных решений доступны на кончиках ваших пальцев, но это особенно верно, когда мы знаем, что мы можем объединить статический полиморфизм, используя шаблоны, с динамическим полиморфизмом, используя виртуальные функции.По сути, мы можем генерировать эти базовые объектные оболочки с виртуальными функциями на лету только для случаев, когда это решение необходимо, без пессимизации случаев, когда это не нужно.
Какуже предложено, boost :: any - отличная модель для того, чего вы хотите достичь.Если вы можете использовать его напрямую, вы должны использовать его.Если вы не можете (например, если вы предоставляете SDK и не можете рассчитывать на соответствие версий Boost от третьих лиц), посмотрите на решение в качестве рабочего примера.
Основная идея boost:: any - делать что-то похожее на то, что вы делаете, только эти оболочки генерируются во время компиляции.Если вы хотите сохранить int в boost :: any, класс сгенерирует класс-оболочку int, который наследуется от базового объекта, который обеспечивает виртуальный интерфейс, необходимый для работы any во время выполнения.
Основная проблема, с которой я сталкиваюсь, заключается в том, как установить / получить значения через указатель на базовый класс ValObject.Сначала я подумал, что могу просто создать множество функций в базовом классе, таких как set_int, get_int, set_string, get_string, set_value_for_key, get_value_for_key и т. Д., И заставить их работать только для правильных типов.Но тогда у меня было бы много случаев, когда функции ничего не делали и просто загрязняли мой интерфейс.
Как вы уже правильно поняли, это, как правило, плохой дизайн.Один контрольный признак неправильного использования наследования - это когда у вас много базовых функций, которые не применимы к вашим подклассам.
Рассмотрите конструкцию потоков ввода-вывода.У нас нет ostreams с такими функциями, как output_int, output_float, output_foo и т. Д., Которые являются непосредственно методами в ostream.Вместо этого мы можем перегрузить оператор << для вывода любого типа данных, который мы хотим, не навязчивым способом.Аналогичное решение может быть достигнуто для вашего базового типа.Вы хотите связать виджеты с пользовательскими типами (например, редактор пользовательских свойств)?Мы можем допустить, что: </p>
shared_ptr<Widget> create_widget(const shared_ptr<int>& val);
shared_ptr<Widget> create_widget(const shared_ptr<float>& val);
shared_ptr<Widget> create_widget(const shared_ptr<Foo>& val);
// etc.
Вы хотите сериализовать эти объекты?Мы можем использовать решение как потоки ввода / вывода.Если вы адаптируете свое собственное решение, например boost :: any, оно может ожидать, что такие вспомогательные функции уже будут там с сохраняемым типом (виртуальные функции в сгенерированном классе-обертке могут вызывать create_widget (T), например,
Если вы не можете быть такими общими, то предоставьте некоторые средства идентификации хранимых типов (например, ID типа) и соответствующим образом обработайте получение / настройку различных типов в клиентском коде на основе этого ID типа.Таким образом, клиент может увидеть, что хранится, и соответственно установить / получить значения для него.
В любом случае, это ваше дело, но вы должны рассмотреть ненавязчивый подход к этому, так как он обычно будет менее проблематичнымнамного более гибкий.