我的程序有一个抽象类BaseNode和2个派生类ChoiceNode和OpponentNode。我想在BaseNode中编写一个纯虚拟函数,称为“returnOpposite”,如果从ChoiceNode调用,应该返回OpponentNode,如果从OpponentNode调用,则应该返回ChoiceNode。

在BaseNode.h中

class BaseNode {
    protected:
        virtual BaseNode& returnOpposite() = 0;
}

在ChoiceNode.h中
#include "BaseNode.h"

class ChoiceNode: public BaseNode {
    OpponentNode& returnOpposite();
}

在OpponentNode.h中
#include "BaseNode.h"

class OpponentNode: public BaseNode {
    ChoiceNode& returnOpposite();
}

我的问题是,Opponent / ChoiceNode需要了解相反的类,这通常可以通过使用前向声明BUT来解决,以便编译器认识到相反的类与BaseNode是协变的,因此需要上下文有关该类的信息。

据我了解,此信息是通过包含适当的头文件来提供的。但是,这样做会导致某种循环依赖。 ChoiceNode需要包含OpponentNode,而后者本身也需要包含ChoiceNode,但是在具有 header 防护的情况下,似乎OpponentNode不会知道ChoiceNode类的声明。

我该如何解决这个明显的问题22?有没有一种方法可以提供有关类的上下文信息而又不涉及循环依赖?

最佳答案

由于您已经发现了循环依赖问题,因此无法使用真正的协变返回类型,正如您所发现的那样。

但是,您可以使用在引入协变量返回类型之前起作用的技术。

首先,我建议将所有类的声明都更改为virtual Node& returnOppositeImpl(),使基类成为纯虚拟的。我还将根据您的类层次结构的其余部分,将函数和所有实现声明为private。然后,您将在每个类returnOpposite中声明一个非虚拟的(或公共(public)的)方法,并使用上述签名。这些函数定义彼此相互屏蔽,因此不需要协变量返回类型,并且它们的实现可以放置在各自的.cpp文件中。该实现是简单的静态或动态强制转换,调用returnOppositeImpl方法。

使用阴影,您将始终在调用站点处调用与静态类型相对应的returnOpposite,因此它将具有正确的引用类型。但是在实现中隐藏了各种Node类之间的链接的实际知识,从而打破了依赖循环。

所以,合计

在BaseNode.h中

class BaseNode {
    private:
        virtual Node& returnOppositeImpl() = 0;
    protected: // Or public:
         Node& returnOpposite() {
            return returnOppositeImpl();
         }
}

在ChoiceNode.h中
#include "BaseNode.h"
class OpponentNode;
class ChoiceNode: public BaseNode {
    private:
        virtual Node& returnOppositeImpl();
    protected: // or public:
        OpponentNode& returnOpposite();
}

在ChoiseNode.cpp中
#include "ChoiseNode.h"
#include "OpponentNode.h"
OpponentNode& ChoiseNode::returnOpposite()
{
  // You can use static cast here, if Node doesn't have virtual
  // members, and/or if you can guarantee further subclasses
  // will properly always return an OpponentNode reference.

  return dynamic_cast<OpponenentNode&>(returnOppositeImpl());
}

OpponentNode.h和OpponentNode.cpp与ChoiseNode实现类似

09-10 16:45