CRTP bei Factory-Methoden mit verschiedener Signatur
-
Hallo,
ich habe zwei Klassen (hier nur Auszuege gezeigt)
class Prob_Nd { protected: Prob_Nd(); void alloc_log_subst_prob(); };und
class Rev_Tip_Nd : public Prob_Nd { private: Rev_Tip_Nd(Rev_Tree* tr, Rev_Tip_NC* node_contnr, string nucl_seq, boost::variant<string, Empty> name); Rev_Tip_Nd(Rev_Tree* tr, Rev_Tip_NC* node_contnr, int num_sites, boost::variant<string, Empty> name); public: static Rev_Tip_Nd* create(Rev_Tree* tr, Rev_Tip_NC* node_contnr, string nucl_seq, boost::variant<string, Empty> name = Empty()); static Rev_Tip_Nd* create(Rev_Tree* tr, Rev_Tip_NC* node_contnr, int num_sites, boost::variant<string, Empty> name = Empty()); };mit den Factory-Methoden
Rev_Tip_Nd* Rev_Tip_Nd::create(Rev_Tree* tr, Rev_Tip_NC* node_contnr, string nucl_seq, boost::variant<string, Empty> name) { Rev_Tip_Nd* n = new Rev_Tip_Nd(tr, node_contnr, nucl_seq, name); n->alloc_log_subst_prob(); // Methode von Prob_Nd, kann erst aufgerufen werden, wenn ein Konstruktor von Rev_Tip_Nd aufgerufen worden ist ... return n; } Rev_Tip_Nd* Rev_Tip_Nd::create(Rev_Tree* tr, Rev_Tip_NC* node_contnr, int num_sites, boost::variant<string, Empty> name) { Rev_Tip_Nd* n = new Rev_Tip_Nd(tr, node_contnr, num_sites, name); n->alloc_log_subst_prob(); // s.o. ... return n; }Da alloc_log_subst_prob() immer nach dem Konstruktor-Aufruf von Rev_Tip_Nd aufgerufen werden muss, frage ich mich, ob man das auch irgendwie so programmieren kann, dass man nicht vergessen kann, alloc_log_subst_prob() in einer Factory-Methode aufzurufen.
Hierbei ist noch wichtig, dass es auch noch zwei andere aus Prob_Nd abgeleitete Klassen Rev_Coal_Nd und Rev_Rec_Nd gibt, wobei die Konstruktoren bzw. Factory-Methoden von Rev_Coal_Nd und Rev_Rec_Nd andere Signaturen als Rev_Tip_Nd haben, z.B.
Rev_Coal_Nd* Rev_Coal_Nd::create(Rev_Tree* tr, Rev_Coal_NC* node_contnr, Rev_Nd* first_old_node, Rev_Nd* second_old_node, boost::variant<string, Empty> name) { Rev_Coal_Nd* n = new Rev_Coal_Nd(tr, node_contnr, first_old_node, second_old_node, name); n->alloc_log_subst_prob(); ... return n; }Ich dachte dabei insbesondere an CRTP, mir ist aber unklar wie das angesichts verschiedener Signaturen der Factory-Methoden realisiert werden kann.
-
Drei Fragen:
1. Muss wirklich der Konstruktor vonRev_Tip_Ndvollständig durch sein? Kann man die Methode nicht im Rumpf desProd_NdKonstruktors aufrufen?
2. Wie stark unterscheiden sich die Funktionssignaturen im Sinne von Anzahl Argumenten und Defaultargumenten?
3. Der Aufruf der Funktion am Ende des Konstruktorrumpfes vonRev_Tip_Ndwürde nichts bringen, oder?Grüssli
-
Dravere schrieb:
Prod_NdDas bestärkt meinen ersten Eindruck: ich finde die Nomenklatur überaus kontraproduktiv.
Was das Problem anbelangt, so wäre anzumerken, daß Methoden, deren Aufruf nur in bestimmten Zuständen des Objektes gültig sind, vermieden werden sollten. Alle derartigen Aktionen sollten in diesem Falle im Konstruktor stattfinden.
Eine Möglichkeit wäre, die notwendige Initialisierungsabfolge durch eine veränderte Klassenstruktur auszudrücken:
class A { protected: struct InnerObject {}; private: InnerObject* innerObj; protected: InnerObject* getInnerObj (void) { return innerObj; } A (InnerObject* _innerObj) : innerObj (_innerObj) { /* initialize innerObj */ } }; class B : public A { protected: struct InnerObject : A::InnerObject { InnerObject (int) {} }; public: B (int i) : A (new InnerObject (i)) {} };Wenn dann das Ganze noch typsicher sein soll (d.h., wenn du in B ohne Cast an
static_cast <B::InnerObject*> (getInnerObj ())kommen können willst), kannst du das hier probieren:struct InnerCBase {}; template <typename T> struct InnerC; template <class B> class C { protected: struct InnerObject {}; private: InnerC <B>* innerObj; protected: InnerC <B>* getInnerObj (void) { return innerObj; } C (InnerC <B>* _innerObj) : innerObj (_innerObj) { /*initialize innerObj */ } }; class D : public C <D> { public: D (int i); }; template <> struct InnerC <D> { InnerC (int) {} }; D:: D (int i) : C <D> (new InnerC <D> (i)) { }