【问题描述】:

可能是常见的,但在这里找不到任何现有主题。

所以我有一个带有许多成员的私有结构的类。我想为单个成员编写 getter 和 setter,但是为每个成员编写一个 getter/setter 会很长且重复...如何轻松通用?

class C {

   public:
       typedef struct S {
             int a, b, c, d, e, f, g, h;
       }S;
       void setS(S new_struct);
       S getS();
       void setSElement(????, int value);
       int  getSElement(????);
    private:
       S data;

}

用什么来代替?????? with 直接引用我想要的 S 的哪个元素(a 到 h)?

不用说,我需要结构体保持结构体而不与我的其他班级成员混在一起,而且我还需要能够一次完全地获取/设置结构体。

提前致谢,

查尔斯

【问题讨论】:

  • 也许并不总是,但如果你想要这样的东西,设计中通常会有问题。
  • 为什么 S 是私有的,如果你为这个成员提供 getter/setter throw C ?
  • 为什么不用数组来代替,所以你为 ???? 提供索引。
  • 1) 为什么 private + get/set :因为需要在 getter/setter 中进行大量检查和转换(检查值一致性,从度数转换为弧度,检查单位一致性和执行其他转换需要时...),但我不希望用户担心
  • 2) 为什么不使用数组:因为我希望 S 的成员有明确的名称,它们都有非常不同的含义,而不仅仅是序列中的相似元素

标签: c++ struct private member getter-setter


【解答1】:

如果您的动机是,那么这是一个坏主意,但是为每个成员编写一个 getter/setter 会很长且重复......

C的用户为每个成员指定明确的名称很有用。几乎所有支持 OOP 的语言都是这样设计的。也许 smalltalk 是个例外。

您还提到您必须对设置器进行验证。 setSElement 函数很快就会变得复杂。

如果您想保持函数调用的类型安全,您将获得更多代码来实现这一点。

话虽这么说,如果你想要什么建议????可能是,一个简单的枚举就可以了。

class C{
  public:
     enum SElement{ a, b ...

     setSElement(SElement member, int value);

【问题讨论】:

    【解答2】:

    用一个函数设置S的特定数据成员 你可以使用这样的界面:

    void setSElement(int S::*field, int val) {
        data.*field = val;
    }
    int getSElement(int S::*field) const {
        return data.*field;
    }
    

    你可以这样使用它:

    C c;
    c.setSElement(&C::S::a, 17);
    c.setSElement(&C::S::b, 16);
    std::cout << c.getSElement(&C::S::a) << "\n";
    

    顺便说一句,在c++中你不需要这样的C方式组合:typedef struct S {} S,你可以写struct S {}

    【问题讨论】:

      【解答3】:

      enumstd::array 可以像这样使用,

      class C {
      public:
          std::array<int, 3> Elems;
          enum class index {a, b, c};
      
          void setElements(const std::array<int, 3>& elems) { Elems = elems;}
          std::array<int, 3> getElements() const { return Elems;}
      
          void setElemAtIndex(index at, int value) { 
              Elems[static_cast<int>(at)] = value;
          }
          int getElemAtIndex(index at) const { 
              return Elems[static_cast<int>(at)];
          }       
      };
      

      并且可以像这样使用;

      C obj;
      obj.setElements(std::array<int, 3>{1, 2, 3});
      auto elems = obj.getElements();
      
      obj.setElemAtIndex(C::index::c, 30);
      auto a = obj.getElemAtIndex(C::index::c);
      

      【问题讨论】:

        【解答4】:

        根据您的要求,您似乎需要一些枚举:

        class C {
           public:
               enum class EIndex {A, B, C, D, E, F, G, H};
               struct S {
                     int get(EIndex) const;
                     int& get(EIndex);
                     int a, b, c, d, e, f, g, h;
               };
               void setS(const S& new_data) { data = new_data}
               const S& getS() const { return data; }
               void setSElement(EIndex index, int value) { data.get(index) = value; }
               int  getSElement(EIndex index) { return data.get(index); }
            private:
               S data;
        }
        
        int C::S::get(EIndex index) const
        {
            const int array[] = {a, b, c, d, e, f, g, h};
            return array[static_cast<int>(index)];
        }
        
        int& C::S::get(EIndex index)
        {
            int* array[] = {&a, &b, &c, &d, &e, &f, &g, &h};
            return *array[static_cast<int>(index)];
        }
        

        【问题讨论】:

          【解答5】:
          #include <stdio.h>
          #include <cstddef>
          
          class C {
            public:
              typedef struct S {
                int a, b, c, d, e, f, g, h;
              } S;
          
              inline void setSElement(std::size_t offset, int value) {
                *(int*)((C::S*)&data + offset) = value;
              }
          
              inline int getSElement(std::size_t offset) {
                return *(int*)((C::S*)&data + offset);
              }
          
            private:
              S data;
          };
          
          int main(int argc, char const* argv[])
          {
            C c;
            c.setSElement(offsetof(C::S, a), 20);
            printf("a = %d\n", c.getSElement(offsetof(C::S, a)));
          
            return 0;
          }
          

          通过宏的简写方法:

          #define SET_S(__e__) inline void setSElement_ ## __e__ (int value) { setSElement(offsetof(C::S, __e__), value); }
          #define GET_S(__e__) inline int getSElement_ ## __e__ () { getSElement(offsetof(C::S, __e__)); }
          
              SET_S(a)
              GET_S(a)
          

          用法:

          C c;
          c.setSElement_a(30);
          printf("a = %d\n", c.getSElement_a());
          

          【问题讨论】: