Was ist eine gute Möglichkeit, die zirkuläre Vererbung hier zu entschlüsseln?Neugierige zirkuläre Vererbung mit Mix-Ins 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(); /* ... */ }
};
Es schlägt fehl (gcc 4.7.0), weil TrafficLight
ist ein unvollständiger Typ wenn HasImportance
versucht davon zu erben.
Das eigentliche Problem ist, dass HasImportance den Typ kennen muss, der von neighbors()
zurückgegeben wird. Wenn HasImportance
erbt von Node
, dann denkt, dass es neighbors()
gibt eine Liste der Node*
, nicht TrafficLight*
und folglich nicht wissen, dass es receive_importance()
auf die Elemente aufrufen können. Ähnlich Problem, wenn HasImportance
überhaupt nicht erbt.
BTW, was ich versuche zu tun ist ein paar Mix-Ins zu helfen, eine Vielzahl von verschiedenen Arten von Graphen einfach zu definieren und jeden Mix-In einzeln zu testen. Für Beispiel sollte ich in der Lage sein, die Knoten-Klasse für ein Diagramm der Ampel zu definieren, indem Sie einfach so etwas wie class TrafficLight : public HasImportance, HasState<3>, virtual Node { }
schreiben.
Ich habe drei Wege gefunden, um dies zu lösen, aber alle scheinen hässlich. (1) static_cast<NodeType*>
. (2) TrafficLight
übergibt seine this
an HasImportance
in seinem Konstruktor. Auf diese Weise muss HasImportance
überhaupt nicht erben; Es speichert nur einen Zeiger auf (ähem) selbst, und der Vorlagenparameter liefert den Typ des Zeigers. (3) Stellen Sie Node
eine Klassenvorlage, wie folgt aus:
template<class NodeType>
class Node {
public:
list<NodeType*> neighbors() { /* ... */ }
}
class TrafficLight : public HasImportance<Node<TrafficLight>> { /* ... */ }
Das kompiliert und es keine unentgeltlichen Kopie this
, vorstellen, aber es scheint ... ein wenig zu neugierig.
Gibt es hier einen Code-Geruch? Sollte ich diese Graphen in einer komplett anderen Art und Weise angehen?
Die Verwendung von 'static_cast (this)' ist * normal * in CRTP. –
kennytm
@KennyTM: Ich würde sogar so weit gehen und sagen, dass dies der Schlüssel bei der Verwendung des CRTP ist – PlasmaHH
Danke. Ich verkneife mich bei der Verwendung von static_cast, weil es so aussieht, als ignoriere ich ein Zeichen (einen "Geruch"), dass etwas tiefer ist falsch. Wenn es in CRTP "normal" ist, werde ich nicht so sehr widerstehen. Dies ist mein erstes CRTP. Können Sie sagen? :) –