C 继承 - 将指针作为参数指向的虚拟函数

C++ inheritance - virtual function that takes in pointer to this class as parameter

本文关键字:虚拟 函数 参数 继承 指针      更新时间:2023-10-16

说我有一个对象 Node,它具有一个函数 addPath(),它希望另一个 Node作为参数。

virtual void Node::addPath(Node * otherNode)
{
     // does something with otherNode
}

现在,说我源自 Node。我们称此DerivedNode,并且具有新功能foo()。我想覆盖addPath方法。我也知道当我调用DerivedNode::addPath时,参数将永远是另一个DerivedNode。这意味着我希望能够在addPath()方法中调用foo()

int DerivedNode::foo(); 
void DerivedNode::addPath(Node * otherNode)
{
     int x = foo();   // no problem
     int y = otherNode->foo()   // BAD! otherNode is typed as Node, not DerivedNode
}

我无法致电otherNode->foo()。我该怎么办?

显然我知道我可以铸造,但这似乎是一个笨拙的新秀解决方案。我们有更优雅的东西吗?我觉得这应该是一个相当普遍的用例。

您必须施放,除非您在基类中设置这样的东西。但是所有派生的类都需要实现它,取决于您的程序。

virtual int foo() = 0;

您无法调用'foo'方法,因为不是基本节点的成员。的确,您可以进行演员,但请确保该类型的节点参数确实是派生的node,否则您将获得例外。是的,您可以从AddPath方法调用x = foo()方法,因为您正在从derivedNode类中拨打电话。

或者您可以将foo()定义为基类中的虚拟方法。要么使其抽象化,但是在这种情况下,您将无法创建节点实例,或者您可以提供默认/空的实现。

让我们假设您的节点类是两种节点类型的抽象类:

  • 您将拥有叶子节点,执行一些功能
  • 您将拥有复合节点,它将存储其他节点

在这种情况下,出现2个问题:

  1. 为什么基类具有" addNode"方法?叶节点对此没有任何用处...
  2. foo()做什么?也许将" addNode"添加到基类中,然后将" foo()"在模板方法中添加是一种很好的方法。

回答这些方法后,您将更清楚地了解这些方法所承担的责任 - 又会给您提示其中(在哪个班级)将它们放置。

如果只有一个派生的类需要foo()操作,则应使用动态铸件(或重新考虑您的设计)。

如果" foo"操作是适用于多个派生类的操作,则应将虚拟方法foo()添加到基类(node)。

  • 如果(几乎)每个派生类都需要某种类型的foo操作,则将foo()方法摘要(pure。)

  • 如果许多派生类都不需要foo()操作,则使其成为基类中的"无操作",因此派生的类不需要foo()可以简单地忽略问题。

下面的代码使用此技术。

class Node
{
    virtual void Node::addPath(Node * otherNode)
    {
         // does something with otherNode
    }
    virtual void foo()
    {
        // nothing to do in the base class
    }
};
class DerivedNode : public Node
{
    void DerivedNode::addPath(Node * otherNode)
    {
        int x = foo();   // no problem
        int y = otherNode->foo(); // Now this works.
    }
    void foo()
    {
        // this is the DervivedNode-specific foo!
        Node::foo(); // just in case the base class has an opinion
        do my foo-ish stuff here;
    }
};