Qual è un buon modo per decodificare l'eredità circolare qui?Curiosa eredità circolare con mix-in in 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(); /* ... */ }
};
non riesce (GCC 4.7.0) perché TrafficLight
è un tipo incompleto quando HasImportance
cerca di ereditare da essa.
Il vero problema è che HasImportance deve conoscere il tipo restituito da neighbors()
. Se HasImportance
eredita da Node
, allora pensa neighbors()
restituisce un elenco di Node*
, non TrafficLight*
, e di conseguenza non sapere che può chiamare receive_importance()
sulle voci. Simile problema se HasImportance
non eredita affatto.
BTW, quello che sto cercando di fare è fare alcuni mix-in per aiutare a definire una varietà di diversi tipi di grafici facilmente e per testare unitamente ogni mix-in separatamente. Per esempio , dovrei essere in grado di definire la classe nodo per un grafico di semafori semplicemente scrivendo qualcosa come class TrafficLight : public HasImportance, HasState<3>, virtual Node { }
.
Ho trovato tre modi per risolvere questo, ma sembrano tutti brutti. (1) static_cast<NodeType*>
. (2) TrafficLight
passa il suo this
a HasImportance
nel suo costruttore. In questo modo, HasImportance
non ha bisogno di ereditare del tutto; memorizza semplicemente un puntatore su (ahem) stesso e il parametro modello fornisce il tipo del puntatore . (3) Fare Node
un modello di classe, come questo:
template<class NodeType>
class Node {
public:
list<NodeType*> neighbors() { /* ... */ }
}
class TrafficLight : public HasImportance<Node<TrafficLight>> { /* ... */ }
che compila e non introduce una copia gratuita di this
, ma sembra ... un po 'troppo curioso.
C'è un odore di codice qui? Devo avvicinarmi a questi grafici in modo completamente diverso con ?
Uso 'statico_cast (questo)' è * normale * in CRTP. –
kennytm
@KennyTM: Mi piacerebbe andare così lontano e dire che questa è la chiave per usare il CRTP – PlasmaHH
Grazie. Mi preoccupo di usare static_cast, perché sembra che sto ignorando un segno (un "odore") che qualcosa di più profondo è sbagliato. Se è "normale" in CRTP, immagino che non resisterò così tanto. Questo è il mio primo CRTP. Puoi dire? :) –