Warum werden mehrfach vererbte functionen mit demselben Namen, aber unterschiedlichen Signaturen nicht als überladene functionen behandelt?

Das folgende Snippet erzeugt während der Kompilierung einen “ambigious call to foo” -Fehler, und ich würde gerne wissen, ob es ein Problem mit diesem Problem gibt, ohne den Aufruf von foo vollständig zu qualifizieren:

#include  struct Base1{ void foo(int){ } }; struct Base2{ void foo(float){ } }; struct Derived : public Base1, public Base2{ }; int main(){ Derived d; d.foo(5); std::cin.get(); return 0; } 

Also, Frage ist wie der Titel sagt. Ideen? Ich meine, folgendes funktioniert einwandfrei:

 #include  struct Base{ void foo(int){ } }; struct Derived : public Base{ void foo(float){ } }; int main(){ Derived d; d.foo(5); std::cin.get(); return 0; } 

Die Regeln für die Mitgliedersuche sind in Abschnitt 10.2 / 2 definiert

Die folgenden Schritte definieren das Ergebnis der Namenssuche in einem classnbereich, C Zuerst wird jede Deklaration für den Namen in der class und in jedem seiner Basisklassenunterobjekte betrachtet. Ein Mitgliedsname f in einem Unterobjekt B verbirgt einen Mitgliedsnamen f in einem Unterobjekt A wenn A ein Basisklassenunterobjekt von B . Alle Deklarationen, die so versteckt sind, werden aus der Betrachtung entfernt . Jede dieser Deklarationen, die durch eine using-Deklaration eingeführt wurde, wird als von jedem Unterobjekt von C , das von dem Typ ist, der die Deklaration enthält, die durch die using-Deklaration bezeichnet wird. Wenn die resultierende Gruppe von Deklarationen nicht alle aus Unterobjekten desselben Typs stammt oder die Gruppe ein nicht statisches Element aufweist und Elemente aus unterschiedlichen Unterobjekten enthält, gibt es eine Mehrdeutigkeit, und das Programm ist schlecht ausgebildet . Andernfalls ist diese Menge das Ergebnis der Suche.

 class A { public: int f(int); }; class B { public: int f(); }; class C : public A, public B {}; int main() { C c; cf(); // ambiguous } 

Sie können also die using Deklarationen A::f und B::f , um diese Mehrdeutigkeit aufzulösen

 class C : public A, public B { using A::f; using B::f; }; int main() { C c; cf(); // fine } 

Der zweite Code funktioniert errorsfrei, da void foo(float) innerhalb des Bereichs von C liegt. Eigentlich d.foo(5); ruft void foo(float) und nicht die int Version.

Die Namenssuche ist eine separate Phase für die Überladungsauflösung .

Die Namenssuche findet zuerst statt. Das ist der process der Entscheidung, für welchen Geltungsbereich der Name gilt. In diesem Fall müssen wir entscheiden, ob d.foo dD::foo oder d.B1::foo oder d.B2::foo . Die Namenssuchregeln berücksichtigen keine functionsparameter oder irgendetwas; Es geht nur um Namen und Bereiche.

Erst wenn diese Entscheidung getroffen wurde, führen wir dann eine Überladungsauflösung für die verschiedenen Überladungen der function in dem Bereich durch, in dem der Name gefunden wurde.

In Ihrem Beispiel würde das Aufrufen von d.foo() D::foo() wenn es eine solche function gäbe. Aber da ist keiner. Also, rückwärts in den Bereichen arbeiten, versucht es die Basisklassen. Nun könnte foo genauso nach B1::foo oder B2::foo schauen, also ist es mehrdeutig.

Aus dem gleichen Grund würden Sie Unklarheiten bekommen, die unqualifizierte foo(5); aufrufen foo(5); innerhalb einer D Mitgliedsfunktion.


Die Wirkung der empfohlenen Lösung:

 struct Derived : public Base1, public Base2{ using Base1::foo; using Base2::foo; 

ist, dass dies den Namen D::foo und zwei functionen identifiziert. Das Ergebnis ist, dass d.foo zu dD::foo wird und dann eine Überladungsauflösung für diese beiden functionen auftreten kann, die durch D::foo identifiziert werden.

Hinweis: In diesem Beispiel sind D::foo(int) und Base1::foo(int) zwei Bezeichner für die eine function; aber im Allgemeinen macht es für den Namenssuchvorgang und den Überladungsauflösungsvorgang keinen Unterschied, ob sie zwei getrennte functionen sind oder nicht.

Wird es für dich funktionieren?

 struct Derived : public Base1, public Base2{ using Base2::foo;}