嵌套C 类的封装困难

encapsulation difficulty in nested c++ classes

本文关键字:封装 嵌套      更新时间:2023-10-16

我们大家都熟悉封装和抽象的概念,但有时这可能会导致障碍,我对技巧或方法或您所谓的解决问题感到好奇。<<<<<<<<<<<。/p>

在这里我们有一个嵌套的C 类:

#include <iostream>
using namespace std;
class Foo {
  public:
    int get_foo_var()
    {
      return foo_var;
    }
    void set_foo_var(int a)
    {
      foo_var = a;
    }
  private:
    int foo_var;
};
class Bar {
  public:
    Foo get_foo()
    {
      return foo;
    }
  private:
    Foo foo;
};
int main()
{
  Bar bar;
  bar.get_foo().set_foo_var(2);
  cout << bar.get_foo().get_foo_var() << endl;
}

如您在此处看到的,get_foo()返回了foo_var(值)的副本,这意味着它不是对原始的副本,而更改它无济于事,因此什么都没有更改。一种解决方案可能以返回参考而不是值的方式更改为get_foo(),但这当然与封装的概念相反。

而无需破坏软件设计原则,解决此问题的解决方案是什么?

更新
有人指出了通过栏类中的函数设置foo_var:

class Bar {
  public:
    void set_foo_var(int a) {
      foo.set_foo_var(a);
    }
  private:
    Foo foo;
};

,但我认为这违反了封装和抽象!抽象的整个概念是" foo"与" foo"answers" bar"有关,与" bar"有关,大多数foo操作都应在foo类中进行,并且某些操作可以在其他类别中应用。那第一个兴趣呢?(Foo操纵与酒吧无关,因此在酒吧操纵foo是愚蠢的!)

您是否要返回某物的副本还是引用某物是一个高级设计决策。两种方式都需要,取决于上下文。

在此特定示例中,您可以在Bar中添加相应的方法来修改其背后的Foo

class Bar {
  public:
    void set_foo_var(int a) {
      foo.set_foo_var(a);
    }
  private:
    Foo foo;
};

这是好还是坏?答案是:我们不能告诉你。通常,很难认真谈论具有" foo"answers" bar"之类的名字的良好类设计。好与坏取决于实际的实际用法场景!:)

让我们从一个纯粹的概念级别看一看。这是您的设计所说的:

  1. 每个bar实例都有一个概念性的foo实体(因为我可以从bar中获得一个foo,而且它的状态取决于我从哪个栏中获得的bar)。
  2. 每个foo实例属于它来自的bar实例(因为在foo上操作更改了它来自的栏 - 下次我从bar中要求foo时,以前的foo更改反映了)。
  3. 一个foo的寿命与其标准相同(因为我可以在酒吧一生中的任何时候要求它,只要栏的存在,我就可以使用它,而get_foo()的呼叫者无法管理一生的寿命返回的foo对象)。

另一种看待它的方法是,Foo已经被设计为BAR内部状态的一部分,即"概念成员变量",无论它是否实际实现。

鉴于您的公共界面已经告诉您的是,如何返回对私人成员的非conter frice 真正的断裂封装?您能否更改实现,以使FOO不是私有成员变量,但仍使用相同的公共界面?是的,你可以。唯一迫使您更改公共接口的实现更改也迫使您更改上述概念接口。

实施经验规则可以被过度应用。移动过去的力学,然后看概念设计。假设您对设计的含义很满意,在这种情况下,我说返回对私人成员变量的引用不会破坏封装。至少这是我的看法。

一种替代方法是将foo和bar紧密耦合。

class Bar {
  public:
  Foo get_foo()
  {
    return foo;
  }
  set_foo(Foo new_foo)
  {
    // Update foo with new_foo's values
    foo = new_foo;
  }
  private:
  Foo foo;
};

在这种情况下,FOO在要求时反映了Bar的内部状态的某些部分,但并未与它来自的Bar绑定。您必须明确调用set_foo()以更新栏。没有该要求,Foo实际上是成员变量,无论您如何实施它。