簡體   English   中英

嵌套c ++類中的封裝困難

[英]encapsulation difficulty in nested c++ classes

我們都熟悉封裝和抽象的概念,但是有時這可能會導致我對這些技巧或方法或解決問題的方法感到好奇的障礙。

這里我們有一個嵌套的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()更改為返回引用而不是值的方式,但這與封裝的概念形成了鮮明的對比。

在不違反軟件設計原則的情況下有什么解決方案?

更新
一個指出通過bar類中的函數設置foo_var的方法:

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

但是我認為這違反了封裝和抽象! 整個抽象概念是,如果“ foo”與“ Foo”相關,而“ bar”與“ Bar”相關,則大多數foo操作應在Foo類中進行,而某些操作可在其他類中進行。 那第一次情景呢? (這種情況下,foo操作與Bar無關,因此在bar中操作foo是愚蠢的!)

您是要返回某物的副本還是對某物的引用是高層設計的決定。 根據上下文,可能需要兩種方式。

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

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

這是好事還是壞事? 答案是:我們無法告訴您。 通常,很難認真討論具有“ Foo”和“ Bar”之類名稱的優秀類設計。 好的和壞的取決於實際的實際使用情況! :)

讓我們從純粹的概念層面來看一分鍾。 這就是您的設計所說的:

  1. 每個Bar實例都有一個概念上的Foo實體(因為我可以從Bar中獲取Foo,並且其狀態取決於我從哪個Bar中獲取它)。
  2. 每個Foo實例都屬於它所來自的Bar實例(因為對Foo進行的操作更改了它來自的Bar-下次我從Bar請求Foo時,會反映以前的Foo的更改)。
  3. 一個Foo與它的Bar具有相同的生存期(因為我可以在Bar的生存期內隨時要求它,只要Bar存在,我就可以使用它,並且get_foo()的調用者不管理返回的Foo的生存期賓語)。

另一種看待它的方式是,Foo已被設計為Bar內部狀態的一部分,即“概念成員變量”,無論它是否實際上是通過這種方式實現的。

給定您的公共接口已經告訴您的內容,對私有成員返回非const引用真的會破壞封裝嗎? 您是否可以更改實現,以使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()來更新Bar。 沒有這個要求,Foo實際上在概念上是成員變量,無論您如何實現它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM