我有一個節點層次結構,其中可能出現「菱形」。將CRTP與虛擬繼承結合使用
每個節點都必須是可克隆的,但我不想寫克隆的方法每一個節點。所以我使用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"; }
};
哪裏都是2線我很好奇。 (行(1)和(2))
如果這兩行都被刪除,由於存在不明確的clone
方法(來自每個父級),因此存在不經意的編譯錯誤。由於我不使用協變返回類型,因此應該爲每個父項使用clone
方法,所以我使用line(1)但它不起作用。仍然含糊不清。
於是我就用線(2)和它的作品。
有沒有一種很好的方式,以避免書寫線(2)?
HERE充滿對ideone工作示例。
有關協變返回的更多細節:任何時候你想調用clone(),* *你已經知道你想要調用它的實例的派生最具體的具體類型,在這種情況下,你不會不需要虛擬方法; *或*你不知道它,在這種情況下,你的代碼無論如何都不能使用任何比'Base *'更具體的返回類型。 –
謝謝你的回答 – relaxxx
@j_random_hacker你是對的 – relaxxx