Warum muss eine überschriebene Funktion in der abgeleiteten Klasse blenden Sie die anderen überladungen der Basis-Klasse?
Betrachten Sie den code :
#include <stdio.h>
class Base {
public:
virtual void gogo(int a){
printf(" Base :: gogo (int) \n");
};
virtual void gogo(int* a){
printf(" Base :: gogo (int*) \n");
};
};
class Derived : public Base{
public:
virtual void gogo(int* a){
printf(" Derived :: gogo (int*) \n");
};
};
int main(){
Derived obj;
obj.gogo(7);
}
Habe diesen Fehler :
>g++ -pedantic-Os test.cpp -o test test.cpp: In function `int main()': test.cpp:31: Fehler: keine passende Funktion für Aufruf von " Abgeleitet::gogo(int)' test.cpp:21: Anmerkung: Kandidaten sind: virtual void Abgeleitet::gogo(int*) test.cpp:33:2: warning: no newline at end of file >Exit-code: 1
Hier die Abgeleitete Klasse die Funktion ist überstrahlt alle Funktionen mit demselben Namen (nicht Unterschrift) in der Basisklasse. Irgendwie ist dieses Verhalten von C++ nicht sehen OK. Nicht polymorph.
Duplizieren: stackoverflow.com/questions/411103/...
geniale Frage, ich habe nur entdeckt das kürzlich zu
Ich denke, Bjarne (aus dem link, den Mac geschrieben) setzen Sie am besten in einem Satz: "In C++, es gibt keine überlastung über Bereiche abgeleitete Klasse Bereiche werden nicht eine Ausnahme zu dieser Allgemeinen Regel."
Link ist gebrochen. Hier ist die richtige (wie jetzt) - stroustrup.com/bs_faq2.html#overloadderived
Auch wollte darauf hinweisen, dass
geniale Frage, ich habe nur entdeckt das kürzlich zu
Ich denke, Bjarne (aus dem link, den Mac geschrieben) setzen Sie am besten in einem Satz: "In C++, es gibt keine überlastung über Bereiche abgeleitete Klasse Bereiche werden nicht eine Ausnahme zu dieser Allgemeinen Regel."
Link ist gebrochen. Hier ist die richtige (wie jetzt) - stroustrup.com/bs_faq2.html#overloadderived
Auch wollte darauf hinweisen, dass
obj.Base::gogo(7);
funktioniert immer noch durch den Aufruf der versteckten Funktion.InformationsquelleAutor fizzbuzz | 2009-10-27
Du musst angemeldet sein, um einen Kommentar abzugeben.
Beurteilung durch die Formulierung der Frage (Sie benutzt das Wort "hide"), wissen Sie bereits, was hier vor sich geht. Das Phänomen heißt "Namen ausblenden". Aus irgendeinem Grund, jedes mal, wenn jemand stellt eine Frage über warum Namen versteckt geschieht, Menschen, die reagieren entweder sagen, dass diese als "Namen ausblenden" und erklären, wie es funktioniert (was Sie wahrscheinlich bereits wissen), oder erklären, wie, um es zu überschreiben (was Sie nie danach gefragt), aber niemand scheint zu kümmern, um die Adresse des eigentlichen "warum" - Frage.
Die Entscheidung, die Logik hinter den Namen versteckt, d.h. warum es tatsächlich entworfen wurde, in C++, ist zu vermeiden, bestimmte eingängig, unvorhergesehene und potenziell gefährliche Verhalten, das stattfinden könnte, wenn die geerbte Reihe von überladenen Funktionen, durften mix mit den aktuellen überlastung in der jeweiligen Klasse. Sie wissen wahrscheinlich, dass in C++ überlast Auflösung funktioniert, indem Sie die besten Funktionen aus der Menge der Kandidaten. Dies erfolgt durch die Zuordnung der Typen der Argumente zu den Typen der Parameter. Die passenden Regeln sein könnte, kompliziert manchmal, und oft zu Ergebnissen führen, die wahrgenommen werden könnte als unlogisch durch eine unvorbereitete Benutzer. Hinzufügen neuer Funktionen, um eine Reihe von bereits bestehenden führen könnten, in einen drastischen Wandel in überlast Auflösung ergibt.
Zum Beispiel, sagen wir, die base-Klasse
B
hat eine member-Funktionfoo
nimmt einen parameter vom Typvoid *
, und alle Aufrufefoo(NULL)
sind entschlossenB::foo(void *)
. Lassen Sie uns sagen, es gibt keine Namen verstecken und dieseB::foo(void *)
ist sichtbar in vielen unterschiedlichen Klassen absteigend vonB
. Allerdings, sagen wir mal in etwa [indirekte, remote] NachkommeD
KlasseB
eine Funktionfoo(int)
definiert ist. Nun, ohne Namen zu versteckenD
hat sowohlfoo(void *)
undfoo(int)
sichtbar und die Teilnahme an überlast Auflösung. Welche Funktion die Aufrufefoo(NULL)
beheben, wenn Sie über ein Objekt vom TypD
? Sie beheben zuD::foo(int)
, daint
ist besser für integral null (d.h.NULL
) als jede Zeiger-Typ. Also, in der gesamten Hierarchie Aufrufefoo(NULL)
lösen einer Funktion, während inD
(und unter) Sie plötzlich lösen zum anderen.Ein weiteres Beispiel ist gegeben in Das Design und Evolution von C++, Seite 77:
Ohne diese Regel, b ' s Zustand wäre teilweise aktualisiert, was zu schneiden.
Wurde dieses Verhalten als unerwünscht, wenn die Sprache entwickelt wurde. Als der bessere Ansatz, es wurde beschlossen, Folgen Sie den "Namen verbergen" - Spezifikation, was bedeutet, dass jede Klasse beginnt mit einem "clean sheet" mit Bezug auf jeder name der Methode erklärt er. Um dieses Verhalten außer Kraft setzen, die eine explizite Aktion seitens des Benutzers erforderlich: ursprünglich ein nochmaliges deklarieren einer geerbten Methode(N) (derzeit veraltet), jetzt eine explizite Verwendung der using-Deklaration.
Wie Sie richtig beobachtet, die in Ihrem original-Beitrag (ich beziehe mich auf das "Nicht-polymorph" Bemerkung), dieses Verhalten kann gesehen werden als eine Verletzung des IS-A Beziehungen zwischen den Klassen. Das ist wahr, aber offenbar damals wurde beschlossen, dass am Ende Namen versteckt sich zum einen das kleinere übel.
Super Antwort! Auch, wie eine praktische Sache, Zusammenstellung würde wahrscheinlich viel langsamer, wenn die Namen zu suchen hatte, gehen den ganzen Weg an die Spitze zu jeder Zeit.
(Alte Antwort, ich weiß.) Jetzt wird
nullptr
ich würde Objekts zum Beispiel, indem Sie sagen: "wenn Sie anrufen wollte, dievoid*
version verwenden, sollten Sie einen Zeiger-Typ". Gibt es ein anderes Beispiel, wo dies schlecht sein?Der name versteckt ist nicht wirklich böse. Die "ist-ein" Beziehung ist immer noch da, und stehen über der Basis-Oberfläche. Also vielleicht
d->foo()
noch nicht mal die "Ist-einBase
", aberstatic_cast<Base*>(d)->foo()
wird, darunter dynamic dispatch.Diese Antwort ist wenig hilfreich, weil dem gegebenen Beispiel verhält sich mit oder ohne etwas zu verbergen: D::foo(int) aufgerufen werden, entweder weil es eine bessere übereinstimmung oder weil es verborgen hat, B:foo(int).
InformationsquelleAutor AnT
Die Regeln für Namensauflösung sagen, Suche halt in den ersten Bereich, in dem ein passender name gefunden wird. An diesem Punkt, der overload resolution rules kick-in zu finden, der das beste match des zur Verfügung stehenden Funktionen.
In diesem Fall
gogo(int*)
zu finden ist (allein) in der Abgeleiteten Klasse Rahmen, und es gibt keine standard-Konvertierung von int nach int*, die Suche fehlschlägt.Die Lösung zu bringen, ist die Basis Erklärungen über eine using-Deklaration in der Abgeleiteten Klasse:
...würde es ermöglichen, die name-lookup-Regeln finden Sie alle Kandidaten und somit die überlast Auflösung würde gehen, wie Sie erwartet.
OP: "Warum muss eine überschriebene Funktion in der abgeleiteten Klasse blenden Sie die anderen überladungen der Basis-Klasse?" Die Antwort: "Weil es funktioniert".
InformationsquelleAutor Drew Hall
Dies ist "By Design". In C++ überlast Auflösung für diese Art von Methode funktioniert, wie die folgenden.
Da Abgeleitet, die nicht über eine entsprechende Funktion namens "gogo" -, überlast-Auflösung schlägt fehl.
InformationsquelleAutor JaredPar
Namen verstecken macht Sinn, weil es verhindert, dass Unklarheiten in der Namensauflösung.
Betrachten Sie diesen code:
Wenn
Base::func(float)
war nicht verstecktDerived::func(double)
in Abgeleiteten, wir würden die Funktion der Basisklasse aufrufen, beim aufrufendobj.func(0.f)
, obwohl ein float gefördert werden können, zu verdoppeln.Referenz: http://bastian.rieck.ru/blog/posts/2016/name_hiding_cxx/
InformationsquelleAutor Sandeep Singh