【问题标题】:Complex object inside another one另一个里面的复杂对象
【发布时间】:2018-04-19 07:17:07
【问题描述】:

我有以下课程

class A {
private:
   B b;
public:
   A();
}

class B {
public:
   void foo();
   void bar();
   void foz();
   ........
}

B 有很多方法。有时需要 A 类的“客户”使用 B 类的方法。我可以返回 B 的引用,但在这种情况下,我应该返回 const 引用,因为返回私有对象的非常量引用并不好编程。如果引用是 const,则无法调用 foo、bar 等,因为它们不是 const。因此,唯一“干净”的方法似乎是使用委托给 B 在 A 中重新创建相同的接口。但是这种方法并不是很好,因为我应该在 A 中重新创建所有接口。作为替代方案,我可以在 A 中将 B 设置为 public,但是它对我来说似乎“奇怪”。这种情况我该怎么办?

【问题讨论】:

  • 为什么不使用继承?
  • 返回非常量引用并不是“糟糕的编程”。参见例如std::vector 是元素访问运算符。您始终可以创建 两个 "getter" 函数来获取 B 对象,一个标记为 const 的函数返回一个 const 引用,另一个返回一个非常量引用。然后编译器会自动选择正确的使用。
  • 可能不好的是使用“getters”会破坏一些封装。但它是否真的“坏”取决于您的设计和用例。
  • 元素访问运算符提供非常量引用,因为您可以根据该值更改向量的值
  • 如果你是直接调用B函数,那为什么要创建A对象直接使用B对象。否则如果A类的客户想通过A对象调用B函数,那么设计上有一些缺陷

标签: c++ design-patterns


【解决方案1】:

那主要是一个封装问题,你想在A类的公共接口中宣传什么。

如果 B 类也是 public 类 - 读取通常可以由 A 类的用户使用,而不是库或框架内部的类 - 如果您希望存在 B 子对象存在于 A 类的公共文档中,如果你想允许对 B 对象进行任何操作,你可以安全地提供一个 getter。

如果上述任何一个条件为假,那么 getter 会破坏封装,您最好在 A 类中定义委托方法。

根据一般设计,声明一个 interface 类(比如 C)可能是有意义的,其中只包含您希望从类 A 中允许的方法,并让 B 是 C 的子类。然后,您可以安全地声明一个返回 C 对象引用的 getter:

class C {
public:
   void foo();  // optionally virtual or pure virtual...
   void bar();
   void foz();
};

class B: public C {
....    // other members not relevant for what is public for A users
};

class A {
private:
   B b;
public:
   A();
   C& getB() {
       return b;
   }
};

【讨论】:

    【解决方案2】:

    解决方案 1。您创建一个 getb() 并返回对 B 的引用。特别是在您的情况下,它的编程还不错。
    方案二、为b的各个对应函数创建接口函数并调用。

    void A::foo()
    {
        b.foo();
    }
    

    【讨论】:

      【解决方案3】:

      您可以将数据成员设为protected 而不是private。文档说 受保护的成员不像 private 成员那样私有,它们只能被声明它们的类的成员访问,但它们不像 public 成员那样公开,它们可以在任何函数protectedmembers(他们是方法成员的数据成员)充当您正在寻找的角色:它们无法从任何地方访问(安全编码实践),但您仍然可以以干净的方式管理它们当它有意义时:

      1. 如果 A 类具有 B 类型的属性,则可以访问 B 的 protectedpublicmembers
      2. friendfunctions 可以同时访问 protectedpublicfriend 所属类的成员。
      3. 在基类名称之前,protected 关键字指定基类的公共和受保护成员是其派生类的受保护成员。

      这里,您对列表的第一项感兴趣:您可以从 A 访问 B' 方法;但 B 仍有保障。

      当我运行以下代码(改编自您的代码)时:

      #include <iostream>
      
      using std::cout;
      using std::endl;
      
      class B {
      public:
          void foo() { cout << "foo" << endl; };
          void bar() { cout << "bar" << endl; };
          void foz() { cout << "foz" << endl; };
      };
      
      class A {
      protected: // <===== THIS IS THE SIGNIFICANT BIT
          B b; 
      public:
          A() {
              b.foo();
              b.bar();
              b.foz();
              cout << "A constructor" << endl;
          };
      };
      
      
      int main(int argc, char** argv) {
          A myA;
          return 0;
      }
      

      我得到以下控制台输出:

      foo
      bar
      foz
      A constructor
      

      这表明我可以从 A 访问 B 的方法。

      【讨论】:

      • 我觉得你没看懂问题
      猜你喜欢
      • 2021-07-22
      • 2021-10-07
      • 1970-01-01
      • 2022-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 2021-12-08
      相关资源
      最近更新 更多