C++ 基于开关访问成员变量的好方法

C++ 基于开关访问成员变量的好方法,c++,coding-style,readability,C++,Coding Style,Readability,我正在编写包含以下模式的几个函数的代码 memberType* var = NULL; switch(someVariable) { case 0: var = &object.MemberVariable1; break; case 1: var = &object.MemberVariable2; break; case 2: var = &object.MemberVariable3; break; } 成员变量的类型相同。在一些开关中,有几十种情况,

我正在编写包含以下模式的几个函数的代码

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}
int offsets[size] = {
*(int*)&staticObject.member1 - *(int*)&staticObject,
*(int*)&staticObject.member2 - *(int*)&staticObject, 
*(int*)&staticObject.member3 - *(int*)&staticObject}
所以函数可以包含

memberType* var = array[index];
而不是开关

1. 我的第一个想法是在类中创建一个包含单个成员变量和数组的联合,这样我就可以访问单个成员或通过数组+索引访问它们。这很难看,乍一看代码并不明显,并且强制以连续的方式声明成员变量。它也不允许我为不同的索引访问相同的成员变量

2. 拥有一个数组,其中包含指向返回单个成员变量的函数的函数指针,迫使我创建大量单行getter函数

3. 有一个静态分配的对象,这样我就可以

sometype array[size] = {member1, member2, member3}
int offsets[size] = {
*(int*)&staticObject.member1 - *(int*)&staticObject,
*(int*)&staticObject.member2 - *(int*)&staticObject, 
*(int*)&staticObject.member3 - *(int*)&staticObject}
并使用它

var = (memberType*)(*(int*)&object + offsets[index]);
太可怕了

有没有一种好方法可以摆脱这种不必要的冗长模式

免责声明:我没有测试示例中使用的代码。这只是为了举例说明


编辑:我忘了提到一件重要的事情:我不想因为序列化而更改类的大小-我还没有理解我正在使用的实现。

只有
开关

  • 在对象的类中,定义
    GetMemberVariableAt(int)
    并在其中移动开关
  • 然后,让您的客户端代码请求
    object.GetMemberVariableAt(someVariable)
  • 如果这样做,那么使用讨厌的开关来获取正确的成员变量就不那么重要了,因为开关将在对象实现内部,而不是在代码中涂抹。而且,您有一个想法,您可以在以后以最小的努力改进它,切换到阵列或您的想法(或者您的性能要求,也许)想要的任何东西

    如果您不控制对象类的源代码,您仍然可以代理它或在它前面放置一个适配器,并向代理或适配器编码


    我在这里给出的解决方案旨在通过降低丑陋因素的重要性,使您更容易在问题中已经提供的备选方案之间进行选择

    我应该补充一点,在
    开关
    和一系列成员引用解决方案之间,我更喜欢
    开关
    ,因为数据重复可能是潜在错误和复杂代码的丰富来源。如果您可以在内部用数组替换成员变量,我会通过
    开关
    ,但如果您必须同时维护数组和
    GetMemberVariableAt
    之外的字段,我强烈建议您不要重复数据。

    您可能需要签出。这将使您能够更干净地实施您的建议(3)

    假设你的班级是这样的

    class X {
    public:
      memberType MemberVariable1;
      memberType MemberVariable2;
      memberType MemberVariable3;
    };
    
    X obj;
    memberType var = obj.*(ptrs[index]);
    
    现在我们将定义一个指向成员变量的指针数组

    typedef memberType X::*MemberVar;
    MemberVar ptrs[3] = {
      &X::MemberVariable1,
      &X::MemberVariable2,
      &X::MemberVariable3
    };
    
    然后可以像这样使用数组

    class X {
    public:
      memberType MemberVariable1;
      memberType MemberVariable2;
      memberType MemberVariable3;
    };
    
    X obj;
    memberType var = obj.*(ptrs[index]);
    

    在C语言中有很多映射实现。为什么不使用其中一个呢?问题是如何存储对成员变量的访问,而不是容器类型或实现为什么不从数组中的成员开始?也就是说,当你似乎真的想要一个数组时,为什么你会有离散的成员?@JoeZ:因为每个变量都有不同的含义,并且在代码的其余部分中使用的方式也不同。该阵列仅对带有这些开关的函数有意义。我正在重构的是旧代码,所以我必须小心。您可以创建一个const&[N],或者使用一个GetMemberAt(int)来执行绑定检查(可能与您的开关相同)。At可能是更好的一个。我的目标是能够以不太容易出错的方式分别声明与输入值关联的返回值。将开关提取到单独的函数并不会使开关本身更具可读性。我不知道在我的脑海中有一种风格能胜过其他风格。你自己提出了许多选择,但你担心它们有多丑陋。我提供了一个解决方案,使解决方案的丑陋性变得不那么重要,让您能够清楚地理解代码,同时让您考虑性能和其他细节。关于您提出的备选方案,我想补充一点,我更喜欢不需要数据冗余的解决方案,即将您的值放在数组和实例字段中。因此,如果您不喜欢切换,请用数组替换字段。为了继续并基于我的上一条评论,我更喜欢
    切换
    而不是混合的字段+数组解决方案,因为数据冗余会给您带来潜在错误的风险,而切换会减少潜在错误的发生,但会以一些冗长为代价。数组解决方案也付出了代价:您的代码可能会变得更加微妙,而可读性是代码中的主要问题。如果字段可以自然地被认为是一个数组,以至于它们更自然地组合在一起,而不是作为类的子类,那么就让数组去吧。否则,我不会太在意
    开关。可读性+最小的潜在bug对我有效。+1。这正是OP试图从零开始发明的东西。太棒了。我第一次听到这个,但这正是我想要的。不过,数组初始化中的分号应改为逗号。