Моя система очень «тяжелая» (много кода), но очень быстрая и очень многофункциональная (кроссплатформенная C ++). Я не уверен, насколько далеко вы хотели бы пойти с вашим дизайном, но вот большая часть того, что я сделал:
DatumState
- Класс, содержащий «enum» для «type», плюс нативное значение, которое является «объединением» среди всех примитивных типов, включая void*
. Этот класс не связан со всеми типами и может использоваться для любых собственных / примитивных типов и типа «ссылка на» void*
. Так как «enum
» также имеет контекст «VALUE_OF
» и «REF_TO
», этот класс может быть представлен как «полностью содержащий» a float
(или некоторый примитивный тип), или как «ссылка, но не не владеющий "float
(или каким-то примитивным типом). (У меня на самом деле есть контексты "VALUE_OF
", "REF_TO
" и "PTR_TO
", поэтому я могу логически хранить значение , эталон, который не может быть нулевым или указатель, который может быть нулевым или нет , и который, как я знаю, мне нужно удалить или нет .)
Datum
- Класс, полностью содержащий DatumState
, но расширяющий интерфейс для поддержки различных «известных» типов (таких как MyDate
, MyColor
, MyFileName
и т. Д.) Эти общеизвестные типы на самом деле хранятся в void*
внутри элемента DatumState
. Однако, поскольку часть enum
в DatumState
имеет контекст «VALUE_OF
» и «REF_TO
», она может представлять «pointer-to-MyDate
» или «value-of-MyDate
».
DatumStateHandle
- Вспомогательный класс шаблона, параметризованный (общеизвестным) типом (например, MyDate
, MyColor
, MyFileName
и т. Д.). Этот метод доступа используется Datum
для извлечения состояния из известного типа. Реализация по умолчанию работает для большинства классов, но любой класс с определенной семантикой для доступа просто переопределяет свою конкретную параметризацию / реализацию шаблона для одной или нескольких функций-членов в этом классе шаблона.
Macros, helper functions, and some other supporting stuff
- Чтобы упростить «добавление» известных типов в мой Datum
/ Variant
, я счел удобным централизовать логику в несколько макросов, предоставить некоторые функции поддержки, такие как перегрузка оператора и установление некоторых других соглашений в моем коде.
В качестве «побочного эффекта» этой реализации я получил массу преимуществ, включая семантику ссылок и значений, параметры «null» для всех типов и поддержку гетерогенных контейнеров для всех типов.
Например, вы можете создать набор целых чисел и проиндексировать их:
int my_ints[10];
Datum d(my_ints, 10/*count*/);
for(long i = 0; i < d.count(); ++i)
{
d[i] = i;
}
Аналогично, некоторые типы данных индексируются строками или перечислениями:
MyDate my_date = MyDate::GetDateToday();
Datum d(my_date);
cout << d["DAY_OF_WEEK"] << endl;
cout << d[MyDate::DAY_OF_WEEK] << endl; // alternative
Я могу хранить наборы элементов (изначально) или наборы Datum
s (упаковывая каждый элемент). В любом случае я могу "развернуть" рекурсивно:
MyDate my_dates[10];
Datum d(my_dates, 10/*count*/);
for(long i = 0; i < d.count(); ++i)
{
cout << d[i][MyDate::DAY_OF_WEEK] << endl;
}
Можно утверждать, что моя семантика "REF_TO
" и "VALUE_OF
" излишня, но они были необходимы для "развертывания набора".
Я сделал это "Variant
" с девятью различными конструкциями, и мой ток является "самым тяжелым" (больше всего кода), но тот, который мне нравится больше всего (почти самый быстрый с довольно маленьким размером объекта) и я осудил остальные восемь проектов для моего использования.
"Минусы" моего дизайна:
- Доступ к объектам осуществляется через
static_cast<>()
от void*
(Тип безопасно и довольно быстро, но
требуется перенаправление; но,
побочным эффектом является то, что дизайн поддерживает
хранилище "null
".)
- Компиляции длиннее из-за
известные типы, которые подвергаются
через интерфейс
Datum
(но вы
можете использовать DatumState
, если вы этого не сделаете
хочу API известных типов).
Независимо от вашего дизайна, я бы порекомендовал следующее:
Используйте "enum
" или что-то, чтобы сказать
Вы " тип ", отдельно от
" значение ". (Я знаю, что вы можете сжать
их в один "int
" или что-то
с битовой упаковкой, но это
медленный доступ и очень сложно
поддерживать как новые типы
введен.)
Опирайтесь на шаблоны или что-то для централизации операций, с
механизм для конкретного типа
(переопределить) обработку (если вы хотите
обрабатывать нетривиальные типы).
Название игры «упрощенное обслуживание при добавлении новых типов» (или, по крайней мере, для меня). Как хорошая курсовая работа, очень хорошая идея, если вы переписываете, переписываете, переписываете, чтобы удерживать или увеличивать свою функциональность, так как вы постоянно удаляете код, необходимый для поддержания система (например, минимизируйте усилия, необходимые для адаптации новых типов к существующей инфраструктуре Variant
).
Удачи!