Problem: Konstruktor für Konversion & abgeleitete Klasse



  • Bitte korregiert mich, wenn ich irgendwo falsch liege:

    Ich habe eine Klasse BASE und eine davon abgeleitete Klasse DERIVED.
    In der Klasse BASE ist ein operator + implementiert mit Operanden dieser Klasse (BASE).

    Wenn ich nun zwei Typen der Klasse DERIVED addieren will (operator +) wird dazu die geerbte operator + aus BASE genutzt.
    Diese benötigt aber Operanden vom Typ BASE.

    Für die Konversion habe ich in jeder Klasse einen Konstruktor mit genau einem Parameter (jeweils der anderen Klasse). Diese funktionieren auch.

    Wenn ich nun aber addiere wird nachweislich nicht der Konstruktor genutzt und es gehen die Informationen aus der abgeleiteten Klasse verloren.

    Wieso?



  • SuhaG schrieb:

    Ich habe eine Klasse BASE und eine davon abgeleitete Klasse DERIVED.
    In der Klasse BASE ist ein operator + implementiert mit Operanden dieser Klasse (BASE).

    Das sollten Referenzen sein, also operator+(const BASE& lhs, const BASE& rhs);

    Wenn ich nun zwei Typen der Klasse DERIVED addieren will (operator +) wird dazu die geerbte operator + aus BASE genutzt.

    Korrekt. Zumindest solange es keinen operator+ im Scope von DERIVED gibt.

    Für die Konversion habe ich in jeder Klasse einen Konstruktor mit genau einem Parameter (jeweils der anderen Klasse).

    Das ist Käse und unnötig. Eine Derived-to-Base-Konvertierung existiert in C++ implizit.

    Wenn ich nun aber addiere wird nachweislich nicht der Konstruktor genutzt

    Richtig, die Konvertierung geschieht implizit.

    und es gehen die Informationen aus der abgeleiteten Klasse verloren.

    Wenn du Value-Parameter verwendest, dann gehen die Informationen tatsächlich verloren. Was hier geschieht bezeichnet man als "slicing", da der Derived-Teil abgeschnitten wird und nur der Base-Teil übrig bleibt. Das resultierende Objekt *ist* danach ein Base-Objekt.

    Verwendest du hingegen Referenz-Parameter, siehst du zwar nur den Base-Anteil, das referenzierte Objekt ist aber nach wie vor ein Derived-Objekt. Mittels eines Casts (static_ bzw. dynamic_) kannst du weiterhin auf den Derived-Teil zugreifen.

    Slicing ist nur selten das was man will und ein Grund dafür, warum man der Regel "Make non-leaf classes abstract" folgen sollte. In diesem Fall kann slicing gar nicht mehr auftreten, da Basisklassen nicht mehr instanziiert werden können.

    Einen Operator+ in einer Hierarchie ist allerdings so oder so problematisch, es sei denn er kann problemlos ausschließlich auf dem Base-Anteil arbeiten. Andernfalls musst du dir ganz genau überlegen, was die Semantik von operator+(BaseType, DerivedType) ist und wie du dafür sorgst, dass dein op+ kommutativ bleibt.



  • Vielen Dank!

    Habe es dank der Erläuterung nun hinbekommen...


Anmelden zum Antworten