类之间的双向引用 - 如何避免彼此相互理解?

时间:2012-11-26 22:37:56

标签: c++ oop

想象一下,有一个派生自一个基类的多个类。所有类都需要相互了解,这不是一个选项,因为它是我正在工作的一个更大的项目。我将使用简化的inventory - item关系作为示例,因为它很简单。

class Inventory : public Base {
    std::vector<Base*> m_items; // These CAN be Items
};

class Item : public Base {
    Base* m_parent; // This CAN be Inventory
};

这两个类显然位于不同的文件中,并且需要使用其基类没有的其他方法。注意单词CAN,而不是MUST,这意味着m_parent和m_items可以是从Base派生的任何类的对象。因此,Item的父级可以是InventoryTreasureChest

tl; dr两个班级必须能够彼此沟通,而不必了解彼此的类型。 如何以及什么是实施此类活动的最佳方式?

3 个答案:

答案 0 :(得分:1)

一种方法是为Base类中的通信类型定义抽象函数。 然后在派生类中实现此函数。 这使您可以处理所需的每种类型的通信类型。

但是对于双向引用,您必须更加谨慎地删除此类对象。 这种类型的体系结构非常容易出错。

对于通信的双向引用可能如下所示: base.h:

class Base {
  void doCommunication(Base *caller) = 0;
};

Inventory.h:

class Inventory;      // forward declaration for Item class
#include "Item.h"

class Inventory : public Base {
   void doCommunication(Base *commCaller) { 
      // check type
      Inventory *invCaller = dynamic_class<Inventory*> (commCaller);
      if(invCaller != nullptr) {
         // called from inventory and you are able to use inventory

         return;  // you can stop here cause commCaller can only be Base class instead but not Item
      }

      Item *itemCaller = dynamic_class<Inventory*> (commCaller);
      if(invCaller != nullptr) {
         // called from item and you are able to use item

         return;  // you can stop here cause commCaller can only be Base class instead but not inventory
      }
   }
};

Item.h看起来非常类似于库存类,必须为项目特定功能覆盖doCommunications。

我还无法测试代码,但它应该可行。 您可以将dynamic_cast转换为所需的目标对象并调用所需的函数。 如果失败,你会得到一个nullptr。

希望它有所帮助。

欢呼声 卢卡斯

答案 1 :(得分:1)

在您的示例中,没有任何实际问题:两个类之间没有直接依赖关系,并且您没有显示实现的任何部分。如果实现实际上需要从相应的其他类访问特定的InventoryItem方法,那么可以采用的方法是将每组操作分解为相应的基类,也可能派生自{{ 1}}并提供合适的功能。

例如

Base

请注意,库存和项目的抽象和独立操作只是考虑因素。接口或实现之间没有任何依赖关系,尽管具体对象实际上可以相互调用。

答案 2 :(得分:0)

两个班级可以“彼此了解”就好了。只是在其用户的头文件中转发声明引用的类,并且只在cpp中包含引用的类头(而不是h)......

<强> A.H:

struct B; // fwd decl

struct A
{
    B* b;

    void fa();
};

<强> A.cpp:

#include "A.h"
#include "B.h"

void A::fa() { b->fb(); }

<强> B.h:

struct A; // fwd decl

struct B
{
    A* a;

    void fb();
};

<强> B.cpp

#include "B.h"
#include "A.h"

void B::fb() { a->fa(); }

这显然是一个无限的运行时循环,但你明白了。