[英]Using CRTP with virtual inheritance
我有一个节点层次结构,可以发生“钻石”。
每个节点都必须是可克隆的,但我不想将克隆方法写入每个节点。 所以我使用CRTP。
class Node
{
public:
Node(){}
Node(Fill*) { }
virtual ~Node() {}
virtual Node * clone() const = 0;
virtual void id() { std::cout << "Node\n"; }
};
//====================================================================
template <typename Base, typename Derived>
class NodeWrap : public Base
{
public:
NodeWrap() { }
NodeWrap(Fill * arg1) : Base(arg1) { }
virtual Node *clone() const
{
return new Derived(static_cast<Derived const &>(*this));
}
};
工作原理如下:
class NodeA : public NodeWrap<Node, NodeA>
{
public:
typedef NodeWrap<Node, NodeA> BaseClass;
NodeA() { }
NodeA(Fill * f) : BaseClass(f) { }
virtual void id() { std::cout << "NodeA\n"; }
};
第一个问题:
“协方差与虚拟继承一起使用”时,VS中存在BUG 。 有没有办法克服这个bug,还有协变类型是clone
方法吗?
我将返回类型更改为Node
而不是Base
。 我可以忍受,但我想将Base
作为返回类型
第二个问题:当多重继承发挥作用时出现问题。 我创建了新的包装器,它virtually
是继承的
template <typename Base, typename Derived>
class NodeWrapVirtual : public virtual Base
{
public:
NodeWrapVirtual() { }
NodeWrapVirtual(Fill * arg1) : Base(arg1) { }
virtual Node *clone() const
{
return new Derived(static_cast<Derived const &>(*this));
}
};
现在建造钻石结构:
class NodeB : public NodeWrapVirtual<Node, NodeB>
{
public:
typedef NodeWrapVirtual<Node, NodeB> BaseClass;
NodeB() { }
NodeB(Fill * f) : BaseClass(f) { }
virtual void id() { std::cout << "NodeB\n"; }
};
//====================================================================
class NodeC : public NodeWrapVirtual<Node, NodeC>
{
public:
typedef NodeWrapVirtual<Node, NodeC> BaseClass;
using BaseClass::clone;
NodeC() { }
NodeC(Fill * f) : BaseClass(f) { }
virtual void id() { std::cout << "NodeC\n"; }
};
和有问题的钻石节点:
class NodeD : public NodeWrap<NodeB, NodeD>,
public NodeWrap<NodeC, NodeD>
{
public:
typedef NodeWrap<NodeB, NodeD> BaseClassB;
typedef NodeWrap<NodeC, NodeD> BaseClassC;
NodeD() { }
NodeD(Fill * f) : BaseClassB(f), BaseClassC(f) { }
using BaseClassB::clone; // (1)
virtual NodeD *clone() const { return new NodeD(*this); } // (2)
virtual void id() { std::cout << "NodeD\n"; }
};
哪两条线我很好奇。 (第(1)和(2)行)
如果两行都被删除,则会出现无意识的编译错误,因为存在模糊的clone
方法(来自每个父级)。 由于我不使用协变返回类型,因此我应该使用每个父类的clone
方法,因此我使用line(1)但它不起作用。 仍然含糊不清。
所以我使用第(2)行,它的工作原理。
有没有一个很好的方法,以避免写线(2)?
这是关于ideone的完整工作示例。
每个虚函数必须在每个派生类中具有唯一的最终覆盖。 这与名称查找无关(要求是函数,而不是名称),因此using
是无关紧要的。
使用多基类的节点类模板:
template <class Derived, class Base1, class Base2>
class node2 : // etc
// or use a variadic template if you have more than two bases
至于协变回报,如果方便的话,它们是完全没必要的。 您始终可以将每个虚拟功能拆分为私有虚拟和公共非虚拟虚拟。 如果你想返回协变智能指针,这很方便,常见的协变返回机制根本不支持。
首先,您应该非常小心地将虚拟继承与虚拟基础内的成员一起使用(请参阅https://stackoverflow.com/a/1193516/1918154,“Effective C ++”,第20项:“避免公共接口中的数据成员”和http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.8 )。 您的node
获取指向未使用的fill
的指针,但看起来您需要它在某处。
当您移动inhertance关系(你的问题是可以解决public virtual
和public
对你的基类) NodeWrap
。
template <typename Base>
class InheritVirtual
: public virtual Base
{};
template <typename... Bases>
class InheritBases
: public Bases...
{
virtual Node* clone() const = 0;
virtual void id() const = 0;
};
class NodeB : public NodeWrap<InheritVirtual<Node>, NodeB>
{
//...
};
class NodeC : public NodeWrap<InheritVirtual<Node>, NodeB>
{
//...
};
class NodeD : public NodeWrap<InheritBases<NodeB,NodeC>, NodeD>
{
//...
};
运行示例 。
由于所谓的统治规则( 虚拟继承中的优势),因此需要InheritBases
中的纯虚方法。
要解决的问题是在多个基础的情况下将参数传递给正确的构造函数的方法。 与Node
(它是一个虚拟基础)不同,可以让NodeB
和NodeC
拥有成员变量和非平凡的构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.