9

免責事項: 私がやろうとしていることを正確に説明することはできませんでした。そのため、例が私の説明よりも明確になることを願っています! より明確にするために、言い直しを提案してください。:)


そのインターフェイスのメソッドのパラメーターのサブクラスを一般的なケースとは別に処理するために、インターフェイスで必要なバージョンよりも具体的なバージョンで関数をオーバーライドすることは可能ですか? (以下の例とより良い説明...)直接実行できない場合、同様の効果を達成するために使用できるパターンはありますか?

#include <iostream>

class BaseNode {};
class DerivedNode : public BaseNode {};

class NodeProcessingInterface
{
public:
    virtual void processNode(BaseNode* node) = 0;
};

class MyNodeProcessor : public NodeProcessingInterface
{
public:
    virtual void processNode(BaseNode* node)
    {
        std::cout << "Processing a node." << std::endl;
    }

    virtual void processNode(DerivedNode* node)
    {
        std::cout << "Special processing for a DerivedNode." << std::endl;
    }
};

int main()
{
    BaseNode* bn = new BaseNode();
    DerivedNode* dn = new DerivedNode();

    NodeProcessingInterface* processor = new MyNodeProcessor();
    // Calls MyNodeProcessor::processNode(BaseNode) as expected.
    processor->processNode(bn);
    // Calls MyNodeProcessor::processNode(BaseNode).
    // I would like this to call MyNodeProcessor::processNode(DerivedNode).
    processor->processNode(dn);

    delete bn;
    delete dn;
    delete processor;

    return 0;
}

私のモチベーション

いくつかの異なる具体的な s を実装できるようにしたいと考えていますNodeProcessor。そのうちのいくつかはすべてのノードを同じように扱い (つまり、インターフェイスに表示されているものだけを実装します)、いくつかは異なるタイプのノードを区別します (のようにMyNodeProcessor)。したがって、インターフェイス メソッド (の一部/サブクラス) をオーバーロードすることにより、2 番目の呼び出しprocessNode(dn)で実装を使用したいと思います。MyNodeProcessor::processNode(DerivedNode)それは可能ですか?

明らかにprocessor、タイプを変更するとMyNodeProcessor*、これは期待どおりに機能しますが、異なるノード プロセッサを交換可能に使用できるようにする必要があります。

processNode(BaseNode)実行時に引数の正確な型をチェックし、それに基づいて分岐する単一のメソッドを用意することで、これを回避することもできます。このチェックを自分のコードに含めるのは、私には洗練されていないように思えます (特に、ノード タイプの数が増え、巨大な switch ステートメントがある場合)。言語が助けになるべきだと思います。


私はC++を使用していますが、必要に応じて(または他の言語でこれがより簡単/異なる場合)、一般的な回答にも興味があります。

4

3 に答える 3

2

いいえ、このままでは無理です。仮想メソッドのディスパッチはコンパイル時に発生します。つまり、プロセッサ ポインターの静的な型、つまりNodeProcessingInterface. その基本型に仮想関数が 1 つしかない場合は、その 1 つの仮想関数 (またはそのオーバーライド実装) だけが呼び出されます。コンパイラには、より優れた機能を実装する派生 NodeProcessor クラスが存在する可能性があるかどうかを判断する方法がありません。

したがって、派生クラスでメソッドを多様化する代わりに、逆の方法で行う必要があります。基本クラスで必要なすべての異なる仮想関数を宣言し、必要に応じてそれらをオーバーライドします。

class NodeProcessingInterface
{
public:
    virtual void processNode(BaseNode* node) = 0;

  //simplify the method definition for complex node hierarchies:
  #define PROCESS(_derived_, _base_)            \
    virtual void processNode(_derived_* node) { \
      processNode(static_cast<_base_*>(node));  \
    }    

  PROCESS(DerivedNode, BaseNode)
  PROCESS(FurtherDerivedNode, DerivedNode)
  PROCESS(AnotherDerivedNode, BaseNode)

  #undef PROCESS

};

class BoringNodeProcessor : public NodeProcessingInterface
{
public:
    virtual void processNode(BaseNode* node) override
    {
        std::cout << "It's all the same.\n";
    }
};

class InterestingNodeProcessor : public NodeProcessingInterface
{
public:
    virtual void processNode(BaseNode* node) override
    {
        std::cout << "A Base.\n";
    }

    virtual void processNode(DerivedNode* node) override
    {
        std::cout << "A Derived.\n";
    }
};
于 2013-05-28T13:25:02.450 に答える
1

型チェックをしたくないのは正しいです。これは、 Open-Closed の原則に違反します。特殊なノード タイプを追加するたびに、このメソッドを変更する必要があるからです。

あなたが説明していることは、プラグイン アーキテクチャやブリッジ パターンに似ています。

オーバーロードではなく継承を使用する場合、つまり、特殊processNode化されたものをのサブクラスに移動するMyNodeProcessorと、必要なものが得られると思います。

EDIT:
または、少し異なる行に沿って、ノードプロセッサをテンプレートクラスにし、部分的な特殊化を使用して必要な動作を取得できます。

于 2013-05-28T13:18:29.900 に答える
0

さて、C++ からの移行が問題ないと思いますが、Objective C では「カテゴリ」と呼ばれるものが必要だと思います。次のリンクが興味深いと思われるかもしれません:ココア/概念/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html

于 2013-05-28T13:47:09.693 に答える