Проблема проектирования, связанная с манипулированием неизвестными типами - PullRequest
2 голосов
/ 13 июля 2010

У меня возникла проблема с дизайном, с которой, я надеюсь, вы, ребята, сможете помочь.У меня есть несколько разных классов, которые имеют различные параметры (более 20 в каждом случае, и они в основном разные, хотя некоторые абсолютно одинаковы, и в этом случае они наследуются от базового класса).Я хочу управлять этими параметрами через пользователя класса ObjectProperties.Каждый класс будет создавать ObjectProperties и заполнять его собственным списком параметров при инициализации класса.Это делается с помощью карты, настроенной следующим образом:

std::map<std::string, [data_type]> // where [data_type] can be an int, float, bool, string etc.

«строка» - это имя параметра, а тип данных - это тип, с которым он связан.Это будет сделано позже для облегчения написания сценариев (вместо 20+ получателей / установщиков).Я уже создал класс ObjectProperties, но он не идеален.У меня есть структура со всеми возможными типами данных с именем DataTypeStruct и переменная для карты в классе ObjectProperties с именем pDataTypeMap;

typedef struct
{
   int* IntValue;
   float* FloatValue;
   bool* BoolValue;
   std::string* StringValue;
}DataTypeStruct;

std::map<std::string, DataTypeStruct> pDataTypeMap;

Когда класс хочет добавить параметр для манипуляции, он вызывает один изследующие функции, которые затем соответствующим образом создают новую структуру и соединяют ее с именем, которое нужно поместить на карту.Функция возвращает true или false в зависимости от того, была ли она в состоянии вставить его или нет (если false, то имя уже существует)

bool AddParam(std::string aName, int* aParam);
bool AddParam(std::string aName, float* aParam);
bool AddParam(std::string aName, bool* aParam);
bool AddParam(std::string aName, std::string* aString);

Причина aParam состоит в том, что указателипотому что требуется, чтобы параметры передавались по ссылке, чтобы ими можно было управлять позже.

Для изменения значения параметра у меня есть аналогичные функции.Как вы можете видеть, это не идеально, так как я потратил некоторое пространство со структурой (где каждая новая структура хранит только int, или bool, или строку, или float), и вызов перегруженных функций небезопасен (я могу«сделать так, чтобы функции имели уникальные имена, но опять же, это не идеально».

Я надеюсь, что объяснил проблему дизайна, с которой я столкнулся (это немного сложно объяснить), и очень хотел быуслышать предложения о том, как решить эту проблему.

Ответы [ 5 ]

4 голосов
/ 13 июля 2010

Я бы предложил сначала взглянуть на boost :: any , boost: вариант , boost :: tuple или boost :: fusion :: vector как «транспортные средства» для вашего [data_type].

2 голосов
/ 13 июля 2010

Похоже, вы пытаетесь заново изобрести boost :: any .

1 голос
/ 13 июля 2010

Кажется, довольно просто иметь 4 карты вместо 1 с 4 наборами данных.Затем ваши методы AddParam () будут выбирать правильную карту на основе перегрузки и одинаковую для ваших Gets.

Вам нужно беспокоиться о том, что они хранят несколько элементов с одинаковым именем, но разных типов.Вы можете либо перебрать все 4 карты, либо сохранить отдельный набор с именами предметов во всем объекте.

0 голосов
/ 13 июля 2010

Здесь предлагается изменить DataTypeStruct на

typedef struct
{
   void* value;
   int type; 
   //e.g. 
   //0 for empty,1 for int*,2 for float*,
   //3 for bool*,4 for string* etc.
}DataTypeStruct;

Вы можете иметь одну AddParam функцию

bool AddParam(std::string aName, void* aParam, int type);

Вы вызываете функцию как

int a;
float b;
bool c;
std::string d;

AddParam("test1", (void*)a, 1);
AddParam("test2", (void*)b, 2);
AddParam("test3", (void*)c, 3);
AddParam("test4", (void*)d, 4);

Чтобы получить значение, вы можете иметь функцию, похожую на следующую

void* GetParam(std::string aName);

И использовал его, позвонив

int a_return = *((int*)GetParam("test1"));
float b_return = *((float*)GetParam("test2"));
bool c_return = *((bool*)GetParam("test3"));
std::string d_return = *((std::string*)GetParam("test3"));

Теперь все выглядит чистым, расширяемым для новых типов, и вы экономите потраченное впустую пространство :)

Счастливого программирования!

0 голосов
/ 13 июля 2010

Чтобы уменьшить использование памяти, используйте объединение вместо структуры для DataTypeStruct.Ничто другое в вашем коде не должно измениться (доступ к членам такой же, как структура).Теперь вашей структуре потребуется только столько памяти, сколько занимает ее самый большой элемент (возможно, дайте или возьмите несколько байтов для заполнения / выравнивания).

Вы также можете использовать универсальный указатель в вашей функции и привести егосоответствующий тип по мере необходимости.Например:

enum data_type {INT, FLOAT, BOOL, STRING};
bool AddParam(std::string aName, void* pData, enum data_type type);

Теперь у вас есть одна функция для обработки всех типов.Используйте значение type, чтобы определить, как повторно навести указатель внутри функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...