【问题标题】:C++ object hierarchy dependencies code designC++对象层次依赖代码设计
【发布时间】:2011-12-12 21:55:38
【问题描述】:

我想创建两个类:object 和 object_manager,但我对它们应该如何查看/包含彼此感到困惑。我听说禁止两个标题相互包含,如果我的代码依赖项有圆圈,那么这是一个糟糕的代码设计,通常它应该像一个层次结构(城镇->房屋->家具和家具不应该知道关于城镇的存在)。

但是这里我有 object_manager,它知道并保存所有对象,并且对象应该有一个创建新对象的选项,但是他们应该调用 object_manager,这将迫使他们知道它的存在,这将创建一个结构中的圆圈,这很糟糕..

这就像一个进程想通过调用操作系统的系统调用来创建一个新进程,所以操作系统和进程是相互了解的......

有没有办法可以在正确的代码设计中实现这一点,或者有时它应该是不好的??

我想也许这些对象应该有一个特殊的地方来存储它们所有的“系统调用”,并且 object_manager 会不时检查它。但也许有更好的方法。

【问题讨论】:

    标签: c++ dependencies system-calls code-design


    【解决方案1】:

    使用前向声明:

    class ObjectManager;
    
    class Object
    {
    private:
       ObjectManager* m_objManager;
       ....
    public:
       ....
    };
    

    在 .cpp 文件中,您可以包含 ObjectManager.h 也可以代替 ObjectManager 制作接口,这将为您提供更多的实现 IObjectManager 的抽象...

    祝你好运:)。

    【讨论】:

      【解决方案2】:

      其实两者都可以实现。不,这并不是很糟糕。这是部分代码。

      假设你有一个头文件

      我的对象.h

      #ifndef _MYOBJECT
      #define _MYOBJECT
      // Declare the Object Manager class in it.
      
      class MyObjectManager; // forward declaration
      
      class MyObject {
            MyObjectManager manager;
            registerSelf(MyObjectManager &m);
      }
      
      #endif _MYOBJECT
      

      现在是 ObjectManager 标头

      #ifndef _MYOBJECT_MANAGER
      #define _MYOBJECT_MANAGER
      
      class MyObject;  // forward declaration
      
      class MyObjectManager {
            private:
                      List list[];
            public:
                      registerObject(MyObject &o);
      };
      
      #endif
      

      对象管理器的实现

      #include <myobject>
      #include <myobjectmanager>
      
      MyObjectManager::manageMyObject(MyObject &o) {
         list += o; /* etc.  */
      }
      

      对象的实现

      #include <myobject>
      #include <myobjectmanager>
      
      
      MyObject::registerSelf(MyObjectManager &manager) {
           this.manager = manager;
           manager.registerObject(*this);
      }
      

      【讨论】:

        【解决方案3】:

        在很多情况下,类需要相互了解。唯一的问题是他们必须部分了解彼此,或者至少有一个班级了解。通常解决问题的方法是使用 forward declarations 。唯一棘手的问题是在 A 类中,您不能声明具有 B 类类型的成员,只能是指针或对 B 类的引用。

        class B;
        class A 
        {
           B* oB;
        
        };
        
        class B
        {
           A oA;
        }:
        

        【讨论】:

          【解决方案4】:

          以下是一些消除标头之间耦合的一般建议:

          转发声明你能做什么。有时,您的 A 类仅通过传递引用或指针来使用其他类(X、Y、..)。因此,在您的A.h 中,您可以声明使用这些 X、Y 返回或参数类型的方法,而编译器不需要知道完整的类型。这意味着A.h 不需要包含X.hY.h

          使用 PImpl 习惯用法,有时将实现与接口分离(不使用虚拟或抽象类)的最佳方法是执行以下操作:


          Foo.h

          class Foo {
          struct Impl;
          Impl* m_impl;
          
          public:
          Foo();
          void SomeMethod();
          
          }
          

          Foo.cpp

          #include "X.h"
          struct Foo::Impl {
          /* actual implementation */
          ...};
          
          Foo::Foo() : m_impl( new Foo::Impl() ) {};
          
          void Foo::SomeMethod() {
          m_impl->SomeMethod();
          }
          

          【讨论】:

            【解决方案5】:

            您所描述的是一个只能存在于另一个对象中的对象。

            实现这一点的一个好方法是使用嵌套类:

            class object_manager {
              public:
              class object {  // object_manager::object. public allows it to be used outside of manager
                public:
                void foo() {
                  object* t = construct(); // can call object_manager methods
                }
              };
            
              private:
              object my_objects[5]; // can create objects
              static object* construct() { return NULL; }
            };
            

            请记住,您仍然可以为 object 和 object_manager 拥有 2 个 cpp 文件。

            【讨论】:

              【解决方案6】:

              CPP 文件可以包含彼此的头文件而不会导致编译问题(从设计的角度来看它是否正确是另一回事,但在你的情况下应该没问题)。这意味着它们可以调用彼此的方法等。

              关于 header 文件,“object manager”头文件很可能包含“object”头文件,因为“object manager”类需要使用“object”类实例。如果“object”头文件需要知道“object manager”类,在“object”头文件中放置“object manager”的前向声明。这样您就可以在“object”头文件中使用指向“object manager”的指针和引用,而无需创建循环包含依赖项。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-04-07
                • 1970-01-01
                • 1970-01-01
                • 2016-11-03
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多