Jaki jest dobry sposób na rozszyfrowanie tutaj dziedziczenia kołowego?Ciekawe okrągłe dziedziczenie z wymieszaniem w 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(); /* ... */ }
};
To nie powiedzie (gcc 4.7.0), ponieważ TrafficLight
jest niekompletny typ gdy HasImportance
próbuje dziedziczą z niego.
Prawdziwy problem polega na tym, że firma HasImportance musi znać typ zwracany przez neighbors()
. Jeśli HasImportance
dziedziczy z Node
, to uważa neighbors()
Zwraca listę Node*
nie TrafficLight*
, a co za tym idzie nie wiedzieć, że można to nazwać receive_importance()
na pozycje. Podobne problem, jeśli HasImportance
nie dziedziczy w ogóle.
BTW, próbuję zrobić kilka miksów, aby pomóc zdefiniować różne rodzaje wykresów z łatwością i osobno przetestować każdy mix-in. Dla przykładu, powinienem móc zdefiniować klasę węzłów dla wykresu świateł drogowych, pisząc po prostu coś w rodzaju class TrafficLight : public HasImportance, HasState<3>, virtual Node { }
.
Wymyśliłem trzy sposoby rozwiązania tego problemu, ale wszystkie wydają się brzydkie. (1) static_cast<NodeType*>
. (2) TrafficLight
przekazuje swój do w swoim konstruktorze. W ten sposób, HasImportance
nie musi w ogóle dziedziczyć; po prostu przechowuje wskaźnik do samego (ahem), a parametr szablonu określa typ wskaźnika . (3) Sprawdź Node
szablonu klasy, takie jak to:
template<class NodeType>
class Node {
public:
list<NodeType*> neighbors() { /* ... */ }
}
class TrafficLight : public HasImportance<Node<TrafficLight>> { /* ... */ }
To kompiluje i nie wprowadza nieuzasadnioną kopię this
, ale wydaje się ... trochę zbyt ciekawy.
Czy jest tu zapach kodu? Czy powinienem podchodzić do tych wykresów w zupełnie inny sposób?
Używanie 'static_cast (this)' jest * normalne * w CRTP. –
kennytm
@KennyTM: Posunąłbym się tak daleko i powiem, że to jest klucz do korzystania z CRTP – PlasmaHH
Dzięki. Skłaniam się do używania static_cast, ponieważ wydaje mi się, że ignoruję znak ("zapach"), że coś głębszego jest nie tak. Jeśli jest to "normalne" w CRTP, myślę, że nie będę się opierać tak bardzo. To jest mój pierwszy CRTP. Możesz mi powiedzieć? :) –