2016-09-21 3 views
3

Ich möchte eine Membervariable einer abgeleiteten Klasse initialisieren und anschließend an den Basisklassenkonstruktor übergeben. Ich habe die folgende Lösung gefunden (auch hier: http://cpp.sh/4uu4q)Initialize Abgeleitete Klassenmitgliedsvariable vor dem Aufruf des Basisklassenkonstruktors. Ist das UB?

1) Hat der folgende Code ein definiertes oder undefiniertes Verhalten (UB)?

2) Ist das, was ich versuche, ein Anzeichen für ein schlechtes Design?

struct Data { 
    int fValue; 

    Data(int value = -1) : fValue(value) 
    {} 
}; 


struct Base { 
    Base(const std::unique_ptr<Data> & derivedData) { 
     std::cout << "Constructing Base derivedData=" << derivedData->fValue << std::endl; 
    } 
}; 


struct Derived : public Base { 
    std::unique_ptr<Data> fData = std::move(fData); 

    Derived() : Base(ConstructData()) 
    {} 

    const std::unique_ptr<Data> & ConstructData() { 
     fData.release(); 
     fData.reset(new Data(777)); 
     std::cout << "in ConstructData: fData->fValue =" << fData->fValue << std::endl; 
     return fData; 
    } 
}; 


int main() { 
    Derived d; 
    std::cout << "In main: d.fData->fValue =" << d.fData->fValue << std::endl; 
    return 0; 
} 
+0

2) Ja, warum muss Ihre Basisklasse über den abgeleiteten in seinem Konstruktor wissen? – user463035818

+0

Die abgeleitete Klasse wird erst aufgebaut, nachdem ihre Basisklassen erstellt wurden. Das ist UB. –

+0

Sie bedienen fData, bevor der Konstruktor aufgerufen wurde, also ist es ein UB. –

Antwort

3

würde Ich mag eine Membervariable einer abgeleiteten Klasse initialisieren, und danach wird es an die Basisklasse Konstruktor übergeben.

In C++ ist die Reihenfolge der Konstruktion der Basisteil (e) vor den abgeleiteten Teilen. Dies liegt daran, dass es weit häufiger der Fall ist, dass die abgeleiteten Teile (möglicherweise) in Bezug auf die Basisteile konstruiert sind. Um dies klar zu definieren, wird die Base-Then-Abgeleitete Reihenfolge angegeben. Verwendung in der Basis abgeleitet ist daher undefiniert.

Wenn Ihre Basis abgeleitete Elemente verwenden soll, können Sie sicherstellen, dass die Reihenfolge in Ordnung ist. Machen Sie auch die Basisklassen "Mitglieder". Beachten Sie, dass boost::base_from_member genau dafür gebaut ist, um dies bequemer zu machen.

Sagen Sie etwas

class member_type{}; 

haben und Sie möchten, dass derived haben ein member_type Mitglied haben, und leiten sich von base. Dann könnten Sie verwenden:

class derived : 
    private boost::base_from_member<member_type>, 
    public base { 
    using my_member_type = private boost::base_from_member<member_type>; 

public: 
    derived(); 
}; 

zu beachten, dass jetzt derived Subklassen sowohl my_member_type und base (in dieser Reihenfolge). Daher kann letzterer das erstere in seiner Konstruktion verwenden.

derived::derived() : 
    my_member_type{3}, 
    base{my_member_type::member} { 
} 
Verwandte Themen