【发布时间】:2014-03-26 12:13:41
【问题描述】:
我有一个节点层次结构,其中可以出现“钻石”。
每个节点都必须是可克隆的,但我不想将克隆方法写入每个节点。所以我使用 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 方法,所以我使用第 (1) 行,但它不起作用。还是模棱两可。
所以我使用第 (2) 行并且它有效。
有什么好的方法可以避免写第 (2) 行吗?
HERE 是 ideone 上的完整工作示例。
【问题讨论】:
标签: c++ crtp virtual-inheritance