0

、、、、Nodeなどの多くのサブクラスで派生した抽象クラスColorがあり、アプリケーションのユーザー データが含まれています。データは、これらのノードの大きなツリーで構成されています。各サブクラスには、固定型の固定数の子があります。たとえば、Material は 1 つの Color 子と 1 つの Texture 子を持つことができます。これらは として保存されますTextureShapeLightNodestd::shared_ptr

現在、各クラスは引数としてsetChildを受け取るメソッドを派生させます。Node各実装は、それに応じて型とその子の型をチェックし、dynamic_cast成功した場合はそれを設定します。

サブクラス化する必要なく、ジェネリックsetChildメソッドを に実装したいと思います。Nodeこのために、各サブクラスは、名前文字列、型文字列 (サブクラスに対応する)、および a へのポインターを与えることにより、コンストラクターでその子を宣言 (または登録) しshared_ptrますNode

あなたは今問題を見ることができます:

  • を使用しますが**SubClass**Nodeこれは悪いことだとわかっていますが、各サブクラスにはtype()クラスを一意に識別するメソッドがあり、登録された子ごとにその型がわかっているため、誤ったポインター型を保存しないように再確認できますダブルポインタ。
  • 実際にはこれを**Nodeではなく で行い*std::shared_ptr<Node>ます。ここで私は正しいことをするかどうか確信が持てません。

質問:

  • タイプがわかっている場合でもashared_ptr<Subclass>で aを設定することはできますか?*shared_ptr<Node>
  • これはあなたがやったであろう方法で設計されていますか?

ありがとう、

エティエンヌ

4

2 に答える 2

0

shared_pr は、あなたが望むことを行う static_pointer_cast と dynamic_pointer_cast を想定していました。ただし、ノード タイプの固定セットがあることを考えると、ビジター パターンを強くお勧めします。シーン グラフを使用しているように見えることを考えると、Visitor の最適な使用法はシーン グラフを使用することであるため、私はそれをお勧めしたいと思います。

class Material;
class Node;
class Color;
class Texture;
class Shape;
class Light;

class Visitor
{
    public:
        virtual void visit(const shared_ptr<Material>& inNode) = 0;
        virtual void visit(const shared_ptr<Color>& inNode) = 0;
        virtual void visit(const shared_ptr<Texture>& inNode) = 0;
        virtual void visit(const shared_ptr<Shape>& inNode) = 0;
        virtual void visit(const shared_ptr<Light>& inLight) = 0;
}

class Node
{
    public:
        virtual void accept(Visitor& inVisitor) = 0;
};

class Color
: public Node
, public boost::enable_shared_from_this<Color>
{
     public:
         virtual void accept(Visitor& inVisitor)
         {
             inVisitor.visit(shared_from_this());
         }
         ...
};

class Texture
: public Node
, public boost::enable_shared_from_this<Texture>
{
     public:
         virtual void accept(Visitor& inVisitor)
         {
             inVisitor.visit(shared_from_this());
         }
         ...
};

class Shape
: public Node
, public boost::enable_shared_from_this<Shape>
{
     public:
         virtual void accept(Visitor& inVisitor)
         {
             inVisitor.visit(shared_from_this());
         }
         ...
};

class Light
: public Node
, public boost::enable_shared_from_this<Light>
{
     public:
         virtual void accept(Visitor& inVisitor)
         {
             inVisitor.visit(shared_from_this());
         }
         ...
};

このパターン全体の目的は、dynamic_cast と同様のことを行うことですが、任意の dynamic_cast の代わりに仮想関数呼び出しのペアを使用して行われるだけです。Node::accept は、オブジェクトの正確なタイプを認識している関数を呼び出す責任があります (つまり、Light::accept は「これ」が Light* であることを認識しています)。次に、「正しい」タイプ情報を使用して訪問者の訪問関数を呼び出します。

このシステムは、少数の型セットで動作する多数のアルゴリズムをサポートするように設計されています。たとえば、 setChild 関数

class SetMaterialChild
: public Visitor
{
    public:
        SetMaterialChild(Material& inMaterial)
        : mMaterial(inMaterial)
        { }

        virtual void visit(const shared_ptr<Color>& inNode)
        {
            mMaterial.mColor = inNode;
        }

        virtual void visit(const shared_ptr<Texture>& inNode)
        {
            mMaterial.mTexture = inNode;
        }

        virtual void visit(const shared_ptr<Shape>& inNode)
        {
            throw std::runtime_error("Materials cannot have shapes");
        }

        virtual void visit(const shared_ptr<Light>& inLight)
        {
            throw std::runtime_error("Materials cannot have lights");
        }


    private:
        Material&    mMaterial)
};



class Material
: public Node
, public boost::enable_shared_from_this<Material>
{
     public:
         virtual void accept(Visitor& inVisitor)
         {
             inVisitor.visit(shared_from_this());
         }

         void setNode(const shared_ptr<Node>& inNode)
         {
             SetMaterialChild v(*this);
             inNode->accept(v);
         }
         ...
};

この訪問者パターンは、最初はアプローチするのが困難です。ただし、ノード タイプの小さなセットの処理が非常に優れているため、シーン グラフで非常に人気があり、問題にアプローチする最も型安全な方法です。

于 2013-09-04T06:27:59.973 に答える