2012-07-03 46 views
6

在這裏解開循環繼承的好方法是什麼?在C++中混合使用好奇的循環繼承

class Node { 
    // ... 
public: 
    list<Node*> neighbors() { /* ... */ } 
    void update() { } 
} 

template<class NodeType> 
class HasImportance : public virtual NodeType { 
    double m_importance = 0.0; 
public: 
    void receive_importance(double imp) { /* ... */ } 
    void give_importance() { 
     for (auto neighbor : this->neighbors()) 
     neighbor->receive_importance(m_importance /* ... */); 
    } 
}; 

class TrafficLight : public HasImportance<TrafficLight>, virtual Node { 
public: 
    list<TrafficLight*> neighbors() { ... } 
    void update() { give_importance(); /* ... */ } 
}; 

它失敗(GCC 4.7.0),因爲TrafficLight是一個不完整的類型 時HasImportance嘗試從它繼承。

真正的問題是HasImportance需要知道由 neighbors()返回的類型。如果從 NodeHasImportance繼承,那麼它認爲neighbors()回報 Node*一個列表,而不是TrafficLight*,因此不 知道,它可以在項目叫receive_importance()。類似 問題如果HasImportance根本不繼承。

順便說一句,我想要做的是做一些混合,以幫助很容易定義各種各樣的圖形 和單獨測試每個混合。例如,對於 示例,我應該能夠通過編寫 (如class TrafficLight : public HasImportance, HasState<3>, virtual Node { })來定義交通信號燈圖的節點類。

我想出了三種方法來解決這個問題,但都顯得很醜陋。 (1) static_cast<NodeType*>。 (2)TrafficLight在其構造函數中將其 this傳遞給HasImportance。這樣, HasImportance根本不需要繼承;它只存儲一個指向(ahem)本身的指針 ,而模板參數提供了指針 的類型。 (3)作出Node類模板,像這樣:

template<class NodeType> 
class Node { 
public: 
    list<NodeType*> neighbors() { /* ... */ } 
} 

class TrafficLight : public HasImportance<Node<TrafficLight>> { /* ... */ } 

,編譯,並沒有引進this, 無償複製,但它似乎......有點太好奇。

這裏有代碼味道嗎?我應該以完全不同的方式處理這些圖表嗎?

+11

在CRTP中使用'static_cast (this)'是* normal *。 – kennytm

+0

@KennyTM:我甚至會走得這麼遠,並說這是使用CRTP的關鍵 – PlasmaHH

+0

謝謝。我對使用static_cast感到畏懼,因爲它似乎忽略了一個標誌(一種「味道」),即某種更深層的錯誤。如果在CRTP中是「正常」的話,我想我不會那麼反感。這是我的第一個CRTP。你能告訴? :) –

回答

1

(3)但有點不同。

template <class NodeType> 
class Node { ... }; 

template<class NodeType> 
class HasImportance : public virtual Node<NodeType> { ... }; 

class TrafficLight : public HasImportance<TrafficLight> { ... }; 

看起來完全直截了當,而不是比CRTP本身更好奇。

+0

謝謝!即使這是一個小小的差異,我也更喜歡這個。與我的版本不同的是,混合插件的「編譯時接口」現在變得簡單而且不受代碼中其他部分的更改影響。 –