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;
}

我的动力

我希望能够实现几个不同的具体NodeProcessors,其中一些将相同对待所有节点(即仅实现界面中显示的内容),其中一些将区分不同类型的节点(如MyNodeProcessor)。因此,我希望通过重载(某些部分/子类)接口方法processNode(dn)来使用实现的第二次调用。MyNodeProcessor::processNode(DerivedNode)那可能吗?

显然,如果我更改processor为类型,MyNodeProcessor*那么这将按预期工作,但我需要能够互换使用不同的节点处理器。

我也可以通过使用一个方法来解决这个问题,该方法processNode(BaseNode)在运行时检查其参数的精确类型并基于此进行分支。在我的代码中包含这个检查对我来说似乎是不雅的(特别是随着节点类型的数量增加并且我有一个巨大的 switch 语句)。我觉得语言应该能够提供帮助。


我正在使用 C++,但如果您愿意(或者如果这在其他语言中更容易/不同),我也对一般答案感兴趣。

4

3 回答 3

2

不,这是不可能的。虚拟方法调度发生在编译时,即使用处理器指针的静态类型,即NodeProcessingInterface. 如果该基类型只有一个虚函数,则只会调用该虚函数(或其覆盖实现)。编译器无法确定是否有派生的 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

你是正确的,你不想进行类型检查。这将违反开闭原则——因为每次添加专用节点类型时,都必须修改此方法。

您所描述的内容听起来类似于插件架构或桥接模式

如果您使用继承而不是重载——即将专门processNode化的子类移动到MyNodeProcessor——我认为这会给你你想要的。

编辑:
或者,沿着稍微不同的路线,您可以使节点处理器成为模板类并使用部分专业化来获得您想要的行为。

于 2013-05-28T13:18:29.900 回答
0

好吧,我认为,只要从 c++ 漂移就可以了,你想要的就是 Objective C 中的“类别”。你可能会发现这个链接很有趣:http: //developer.apple.com/library/mac/#documentation/ Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html

于 2013-05-28T13:47:09.693 回答