1

1 つの基本クラスから派生した複数のクラスがあると想像してください。すべてのクラスはお互いを知る必要がありますが、これはオプションではありません。これは、私が取り組んでいる少し大きなプロジェクトだからです。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
};

これらの 2 つのクラスは明らかに異なるファイルにあり、基本クラスにはないメソッドを相互に使用する必要があります。MUST ではなく、CAN という単語に注意してください。これは、m_parent と m_items が Base から派生した任意のクラスのオブジェクトになる可能性があることを意味します。したがって、Item の親は または のいずれInventoryかになりますTreasureChest

tl;dr 2 つのクラスは、互いの型を知らなくても、互いに通信できなければなりません。そのような活動を実施する最善の方法は何ですか?

4

3 に答える 3

1

あなたの例では、実際の問題はありません.2つのクラスの間に直接的な依存関係はなく、実装の一部も示していません。実装が実際にそれぞれ他のクラスの特定InventoryItemメソッドにアクセスする必要がある場合は、操作の各セットをそれぞれの基本クラスに分解し、Base適切な関数から派生させて提供することもできます。

例えば

// base.h
class Base {
public:
    virtual ~Base();
};

// abstractitem.h
class AbstractItem: public Base {
public:
    virtual int weight() const = 0;
};

// abstractinventory.h
class AbstractInventory: public Base {
public:
    virtual int totalWeight() const = 0;
};

// item.h
class Item: public AbstractItem {
public:
    int weight() const;
    // uses of AbstractInventory
};

// inventory.h
class Inventory: public AbstractInventory {
    void addItem(AbstractItem const* item);
    int totalWeight() const;
    // uses of AbstractItem
};

インベントリとアイテムの抽象的で独立した操作は除外されていることに注意してください。具体的なオブジェクトは実際に相互に呼び出すことができますが、インターフェイスまたは実装の間に依存関係はありません。

于 2012-11-26T23:56:42.647 に答える
1

1 つの方法は、Base クラスで通信のタイプの抽象関数を定義することです。次に、この関数を派生クラスに実装します。これにより、必要なタイプごとに通信の種類を処理できます。

ただし、双方向の参照では、そのようなオブジェクトの削除についてより注意する必要があります。このタイプのアーキテクチャは、非常にエラーが発生しやすいものです。

通信を伴う双方向参照の場合は、次のようになります。base.h:

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

在庫.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 が返されます。

それが役に立てば幸い。

乾杯ルーカス

于 2012-11-26T22:45:21.500 に答える
0

2つのクラスは「お互いを知る」ことができます。ユーザーのヘッダーファイルで参照クラスを前方宣言するだけで、cpp(hではなく)に参照クラスヘッダーのみをインクルードします。

ああ:

struct B; // fwd decl

struct A
{
    B* b;

    void fa();
};

A.cpp:

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

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

Bh:

struct A; // fwd decl

struct B
{
    A* a;

    void fb();
};

B.cpp

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

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

これは明らかに無限のランタイムループですが、要点はわかります。

于 2012-11-27T00:11:28.430 に答える