Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 嵌套c+中的封装困难+;班级_C++_Encapsulation_Abstraction - Fatal编程技术网

C++ 嵌套c+中的封装困难+;班级

C++ 嵌套c+中的封装困难+;班级,c++,encapsulation,abstraction,C++,Encapsulation,Abstraction,我们都熟悉封装和抽象的概念,但有时这可能会导致一个障碍。我很好奇解决问题的技巧或方法,或者你所说的任何东西 这里有嵌套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; }

我们都熟悉封装和抽象的概念,但有时这可能会导致一个障碍。我很好奇解决问题的技巧或方法,或者你所说的任何东西

这里有嵌套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;
}

但我认为这违反了封装和抽象!抽象的整个概念是,如果“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”这样的名字来认真地谈论好的类设计。什么是好的和坏的取决于实际的、真实的使用场景!:)

让我们从一个纯粹的概念层面来看一分钟。这就是您的设计所说的:

  • 每个酒吧实例都有一个概念性的Foo实体(因为我可以从酒吧中获取Foo,其状态取决于我从哪个酒吧获取Foo)
  • 每个Foo实例都属于它来自的Bar实例(因为对Foo的操作会更改它来自的Bar—下次我从Bar请求Foo时,会反映以前Foo的更改)
  • Foo的生存期与它的Bar相同(因为我可以在Bar的生存期内的任何时候请求它,只要Bar存在,我就可以使用它,get_Foo()的调用方不管理返回的Foo对象的生存期)
  • 另一种看待它的方式是,Foo已经被设计为Bar内部状态的一部分,一个“概念成员变量”,而不管它是否真的以这种方式实现

    考虑到您的公共接口已经告诉您的内容,向私有成员返回非常量引用如何真正破坏封装?能否更改实现,使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\u foo()
    来更新工具栏。如果没有这一要求,Foo实际上在概念上就是一个成员变量,不管您如何实现它。

    为什么您认为返回引用违反了封装?@Brian:这种担心并非毫无根据。事实上,将非常量引用返回到私有成员通常会破坏封装(那么您也可以将该成员设置为非私有)。但这要看情况而定。@BrianBi这有点像公私观念。通过将某些内容设置为“私有”,可以限制对原始数据的直接访问。获取引用正是提供原始数据。不是吗?@ChristianHackl但在这种情况下,他希望客户端能够修改内部
    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;
    };