Хороший способ доступа к переменным-членам на основе переключателя

Я работаю над кодом, который содержит несколько функций со следующим шаблоном

memberType* var = NULL;
switch(someVariable)
{
case 0: var = &object.MemberVariable1; break;
case 1: var = &object.MemberVariable2; break;
case 2: var = &object.MemberVariable3; break;
}

Переменные-члены одного типа. В некоторых коммутаторах есть несколько десятков случаев, которые загромождают тело функции тем, что в основном представляют собой данные. Я хотел бы создать массив, карту или что-то подобное, чтобы я мог получить доступ к членам на основе входного значения.

Я думаю о том, чтобы иметь что-то вроде

sometype array[size] = {member1, member2, member3}

чтобы функция могла содержать

memberType* var = array[index];

вместо выключателя.

1.
Моей первой мыслью было создание объединения в классе, которое содержит отдельные переменные-члены и массив, поэтому я могу получить доступ либо к отдельным членам, либо получить к ним доступ через массив + индекс. Это некрасиво, на первый взгляд неочевидно из кода и вынуждает члены-члены объявляться последовательно. Это также не позволяет мне получить доступ к одной и той же переменной-члену для разных индексов.

2.
Наличие массива, содержащего указатели на функции, которые возвращают отдельные переменные-члены, вынуждает меня создавать тонны однорядных функций получения.

3.
Имея статически размещенный объект, чтобы я мог сделать что-то вроде

int offsets[size] = {
*(int*)&staticObject.member1 - *(int*)&staticObject,
*(int*)&staticObject.member2 - *(int*)&staticObject,
*(int*)&staticObject.member3 - *(int*)&staticObject}

и использовать это

var = (memberType*)(*(int*)&object + offsets[index]);

это ужасно

Есть ли хороший способ избавиться от этого ненужного многословного шаблона?

Отказ от ответственности: я не тестировал код, используемый в примерах. Это просто для иллюстрации.


Редактировать: Я забыл упомянуть одну важную вещь: я не хочу менять размер класса из-за сериализации — мне еще предстоит понять реализацию, с которой я работаю.

3

Решение

Вы можете проверить указатели на участников. Это позволит вам реализовать ваше предложение (3) более четко.

Допустим, ваш класс выглядит следующим образом.

class X {
public:
memberType MemberVariable1;
memberType MemberVariable2;
memberType MemberVariable3;
};

Теперь мы определим массив указателей на переменные-члены.

typedef memberType X::*MemberVar;
MemberVar ptrs[3] = {
&X::MemberVariable1,
&X::MemberVariable2,
&X::MemberVariable3
};

Тогда вы можете использовать массив, как это.

X obj;
memberType var = obj.*(ptrs[index]);
6

Другие решения

Просто инкапсулировать switch:

  1. В классе объекта определите GetMemberVariableAt(int) и переместите переключатель туда.
  2. Затем попросите ваш код клиента object.GetMemberVariableAt(someVariable),

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

Если вы не управляете исходным кодом класса вашего объекта, вы все равно можете проксировать его или поставить перед ним адаптер, а также код для прокси или адаптера.


Решение, которое я здесь предлагаю, призвано упростить выбор между альтернативами, которые вы уже предлагаете в своем вопросе, за счет снижения важности фактора уродства.

Я должен добавить, что между switch и массив решений ссылок на членов, я предпочитаю switchпотому что дублирование данных может быть богатым источником скрытых ошибок и сложного кода. Если ты можешь замещать переменные-члены с массивом внутри, я бы пошел на это через switch, но если вам нужно поддерживать как массив, так и поля снаружи GetMemberVariableAtЭто дублирование данных, против которого я бы настоятельно рекомендовал.

4

По вопросам рекламы [email protected]