Identische virtuelle Funktion aus zwei Basisklassen, kann man nur eine davon überschreiben?
-
Ich habe einen Fall wo eine Klasse X die selbe virtuelle Funktion (selber Name+Signatur) von zwei Basisklassen erbt. Eine der beiden soll nun überschrieben werden, die andere aber nicht.
Geht das irgendwie?
Also konkret möchte ich das machen:
struct A { virtual void foo() = 0; }; struct AImpl : A { virtual void foo() final {}; // dieses final ist einigermassen wichtig }; struct B { virtual void foo() = 0; }; struct X : AImpl, B { void B::foo() final { AImpl::foo(); } }; void test() { X x; x.foo(); }
MSVC frisst das auch in genau dieser Form. Die Frage ist: geht das irgendwie mit Standard C++? Ich weiss dass ich eine Zwischenklasse verwenden kann ala
struct A { virtual void foo() = 0; }; struct AImpl : A { virtual void foo() final {}; }; struct B { virtual void foo() = 0; }; struct BX : B { virtual void foo() final { fooX(); } virtual void fooX() = 0; }; struct X : AImpl, BX { void fooX() final { AImpl::foo(); } using AImpl::foo; }; void test() { X x; x.foo(); }
Aber das ist halt IMO ziemlich hässlich und unnötiges Rauschen.
-
@hustbaer sagte in Identische virtuelle Funktion aus zwei Basisklassen, kann man nur eine davon überschreiben?:
Die Frage ist: geht das irgendwie mit Standard C++?
Mir fällt dazu keine Lösung ein.
Musst du von AImpl ableiten, oder kann es auch ein Member sein?
Welche MSVC Version lässt das zu? /permissive:- ? Nach welchem Standard?
-
@hustbaer sagte in Identische virtuelle Funktion aus zwei Basisklassen, kann man nur eine davon überschreiben?:
Aber das ist halt IMO ziemlich hässlich und unnötiges Rauschen.
Könnte das hier vielleicht mit etwas weniger Rauschen das tun, was du erreichen willst?
struct AImplBase : A { virtual void foo() {}; }; struct AImpl : AImplBase { virtual void foo() final { foo(); }; // dieses final ist einigermassen wichtig }; ... struct X : AImplBase, B { void foo() final { AImplBase::foo(); } };
AImplBase
halt für die Fälle, wo manfoo
doch noch überschreiben will.
-
Gerade im Stroustrup nachgelesen (C++11 §21.3.5), es müssen alle
foo
s überschrieben werden. D.h. entweder inAImpl
final
nutzen, oder in Xfoo
überschreiben.
-
@manni66 Ja, muss ableiten. Welche MSVC Versionen weiss ich nicht genau. Ging schon bei 2005 und geht bei 2019 noch. Und ja, geht auch mit
/permissive-
. Ich nehme an dass MS das eingebaut hat damit es einfacher wird COM Objekte zu implementieren die verschiedene Interfaces implementieren wo gleichnamige Funktionen mit unterschiedlicher Bedeutung vorkommen.
-
@Finnegan
Nö, ist keine Lösung.AImpl
ist die gemeinsame Basisklasse von der abgeleitet wird und in dieser sollte die Methodefinal
sein."Doch noch überschreiben" ist ja gerade unerwünscht weil es überhaupt keinen Sinn macht. Die Methode ist bloss virtuell weil
A
eine reine Interface-Klasse ist, nicht weil man die Methode in abgeleiteten Klassen überschreiben können sollte.
-
@hustbaer sagte in Identische virtuelle Funktion aus zwei Basisklassen, kann man nur eine davon überschreiben?:
@Finnegan
Nö, ist keine Lösung.AImpl
ist die gemeinsame Basisklasse von der abgeleitet wird und in dieser sollte die Methodefinal
sein.Ja verstehe. Ich dachte es wäre lediglich wichtig, dass die Funktion "in der Basisklasse, von der abgeleitet wird"
final
ist. Das wäre bei mir mitAImpl
immer noch der Fall, allerdings nicht mehr als "gemeinsame Basisklasse". Das wäre dannAImplBase
ohnefinal
."Doch noch überschreiben" ist ja gerade unerwünscht weil es überhaupt keinen Sinn macht. Die Methode ist bloss virtuell weil
A
eine reine Interface-Klasse ist, nicht weil man die Methode in abgeleiteten Klassen überschreiben können sollte.Mit "überschreiben" meine ich auch das Implementieren abstrakter Funktionen. Nach meinem Verständnis, wie Standard-C++ das hier interpretiert (ohne den in Zeile 14 qualifizierten Namespace
B::foo
), werden hier inX
zwei eigentlich individuelle Member-Funktionen gleichzeitig überschieben, auch wenn sie keinen gemeinsamen Ursprung haben:AImpl::foo
undB::foo
(abstrakt). Erstere schlägt wegen demfinal
fehl. Für mich ein Fall von "doch noch überschreiben".
-
Also ich bin mir nicht sicher, aber vielleicht mit enable_if. Dann wenn von den Basisklassen abgeleitet wird.
struct B : public A1<true>, public A2<false>
oder so etwas.
-
@Finnegan sagte in Identische virtuelle Funktion aus zwei Basisklassen, kann man nur eine davon überschreiben?:
Nach meinem Verständnis, wie Standard-C++ das hier interpretiert (ohne den in Zeile 14 qualifizierten Namespace B::foo), werden hier in X zwei eigentlich individuelle Member-Funktionen gleichzeitig überschieben, auch wenn sie keinen gemeinsamen Ursprung haben: AImpl::foo und B::foo (abstrakt). Erstere schlägt wegen dem final fehl. Für mich ein Fall von "doch noch überschreiben".
Ja, klar, das sind die Regeln. Ich wollte wissen ob man die irgendwie aushebeln kann, so dass eben nur
B::foo
überschrieben wird. WeilA::foo
ja schon final ist.Ich kenne keine direkte Möglichkeit in Standard C++, ihr auch nicht, also wird's wohl nicht gehen. Wollte nur sicher gehen - ich weiss ja auch lange nicht alles über C++ - speziell aktuellere Standards.
-
@titan99_ sagte in Identische virtuelle Funktion aus zwei Basisklassen, kann man nur eine davon überschreiben?:
Also ich bin mir nicht sicher, aber vielleicht mit enable_if. Dann wenn von den Basisklassen abgeleitet wird.
struct B : public A1<true>, public A2<false>
oder so etwas.
Verstehe ich ehrlich gesagt nicht. Ich habe zwei reine Interface-Klassen,
A
undB
. ZuA
gibt es eine Basisklasse (AImpl
in meinem Beispiel) die für quasi alles Default-Implementierungen hat, wovon vielefinal
sein sollen, weil es Quatsch wäre sie zu überschreiben (und solcher Quatsch-Code existiert und gefunden wurde und wir neuen Quatsch-Code vermeiden möchten).A
undB
haben jeweils die Funktionfoo
- und in beiden wird sie benötigt (es gibt Komponenten die mitA
arbeiten undfoo
brauchen und welche die mitB
arbeiten undfoo
brauchen).Wenn ich dich richtig verstehe meinst du ich sollte ein Interface
BWithoutFoo
machen (A2<false>
). Klar, das ginge dann. Nur ... mit was befüttere ich dann die Komponenten die mitB
arbeiten? Die können mitBWithoutFoo
nixe anfangen.