我的程序有一个抽象类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需要知道相反的类,通常可以使用前向声明来解决,但是为了让编译器能够识别出相反的类与BaseNode是协变的,它需要关于班级的背景信息。
据我了解,此信息是通过包含相应的头文件来提供的。但是,这样做会导致某种循环依赖。 ChoiceNode需要包含OpponentNode,它本身需要包含ChoiceNode,但是有了头部保护,似乎OpponentNode不会知道ChoiceNode类声明。
如何解决这个明显的捕获-22?有没有办法提供有关类的上下文信息而不涉及循环依赖?
答案 0 :(得分:1)
returnOpposite()
方法的所有两个可覆盖的都应具有相同的返回类型。
否则你的代码根本不会编译,这个抽象方法virtual Node& returnOpposite() = 0;
在派生类中没有实现。
所以你的课程应该是这样的:
class BaseNode {
protected:
virtual BaseNode* returnOpposite() = 0;
}
class ChoiceNode: public BaseNode {
virtual BaseNode* returnOpposite() override;
}
class OpponentNode: public BaseNode {
virtual BaseNode* returnOpposite() override;
}
更新(感谢@DaveS评论):如果这两种类型都是协变的(如在草图中),那么以下内容将正常工作:
class BaseNode {
protected:
virtual BaseNode* returnOpposite() = 0;
}
class OpponentNode; // forward declaration
class ChoiceNode: public BaseNode {
virtual OpponentNode* returnOpposite() override;
}
class OpponentNode: public BaseNode {
virtual ChoiceNode* returnOpposite() override;
}
请注意,我在这里返回指向实例而不是引用的指针。
答案 1 :(得分:1)
由于您已识别出循环依赖性问题,因此您无法使用真正的变体返回类型,如您所发现的那样。
但是,您可以使用在引入协变返回类型之前有效的技术。
首先,我建议将所有类中的声明更改为virtual Node& returnOppositeImpl()
,使基类纯虚拟。我还会根据类层次结构的其余部分将函数和所有实现声明为private
。然后,您将在每个类returnOpposite
中声明一个非虚拟保护(或公共)方法,并使用上面描述的签名。这些函数定义因为它们相互影响而不需要共变量返回类型,并且它们的实现可以放在它们各自的.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实现