C++对象层次结构-如何管理循环依赖?

4
我想创建两个类:一个对象和一个对象管理器,但我不确定它们应该如何相互查看/包含。我听说两个头文件相互包含是被禁止的,如果我的代码依赖关系存在循环,则这是一种糟糕的代码设计,并且通常应该像层次结构(城镇->房子->家具,家具不应知道城镇的存在)一样。
但是这里有一个对象管理器,它知道并保存所有的对象,而对象应该有一个选项来创建新的对象,但是然后它们应该调用对象管理器,这将迫使它们知道它的存在,这将在结构中创建一个循环,这是不好的。
这就像一个进程想通过调用操作系统系统调用来创建一个新进程,因此操作系统和进程彼此了解。
是否有一种正确的代码设计实现方式,或者有时只是不好?我认为也许对象应该有一个特殊的地方,它们将在那里存储所有的“系统调用”,而对象管理器会不时地检查它,但也许还有更好的方法。
6个回答

1

使用前向声明:

class ObjectManager;

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

在 .cpp 文件中,您可以包含 ObjectManager.h。另外,您可以使用接口来代替 ObjectManager,这将为实现提供更多的抽象,命名为 IObjectManager。

1

实际上可以实现这两个功能。并且它并不是真的很糟糕。这里是一些部分代码。

假设你有一个头文件。

myobject.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);
}

0

以下是一些消除头文件耦合的常规建议:

尽量使用前向声明。有时候你的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();
}

0

有很多情况下,类需要相互了解。唯一的问题是它们必须部分地或至少一个类知道另一个类。通常解决这个问题的方法是使用前向声明。唯一棘手的问题是在A类中,您不能声明一个类型为B类的成员,只能声明指向B类的指针或引用。

class B;
class A 
{
   B* oB;

};

class B
{
   A oA;
}:

0
你所描述的是一个只能存在于另一个对象内部的对象。
实现这个的好方法是使用嵌套类:
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; }
};

请记住,您仍然可以为对象和对象管理器拥有2个cpp文件。


0

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

关于头文件,"对象管理器"头文件很可能会包含"对象"头文件,因为"对象管理器"类需要处理"对象"类实例。如果"对象"头文件需要了解"对象管理器"类,请在"对象"头文件中放置一个"对象管理器"的前向声明。这样,您就可以在"对象"头文件中使用指针和引用来访问"对象管理器",而不会创建循环包含依赖关系。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接