Funktion mit demselben Namen, aber unterschiedlicher Signatur in abgeleiteten Klasse
-
03-07-2019 - |
Frage
Ich habe eine Funktion mit dem gleichen Namen, aber mit unterschiedlicher Signatur in einer Base und abgeleiteten Klassen. Wenn ich versuche, die Basisklasse Funktion in einer anderen Klasse zu verwenden, das von der abgeleiteten erbt, erhalte ich einen Fehler. Siehe den folgenden Code:
class A
{
public:
void foo(string s){};
};
class B : public A
{
public:
int foo(int i){};
};
class C : public B
{
public:
void bar()
{
string s;
foo(s);
}
};
ich die folgende Fehlermeldung aus den gcc-Compiler:
In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int)
Wenn ich int foo(int i){};
von Klasse B
entfernen, oder wenn ich es von foo1
umbenennen, funktioniert alles einwandfrei.
Was ist das Problem mit diesem?
Lösung
Funktionen in abgeleiteten Klassen, die Funktionen in Basisklassen nicht außer Kraft setzen, die jedoch in demselben Namen verbergen andere Funktionen des gleichen Namens in der Basisklasse.
Es ist allgemein schlechte Praxis zu haben, haben Funktionen in abgeleiteten Klassen betrachtet, die die gleichen Namen wie Funktionen in der Bass-Klasse haben, die nicht dazu bestimmt sind, die Basisklasse Funktionen wie außer Kraft zu setzen, was Sie sehen normalerweise nicht erwünschtes Verhalten sind. Es ist in der Regel bevorzugt, verschiedene Funktionen verschiedene Namen zu geben.
Wenn Sie die Basis-Funktion aufzurufen benötigen Sie den Anruf Umfang müssen durch A::foo(s)
verwenden. Beachten Sie, dass dies würde auch jeden virtuellen Funktionsmechanismus für A::foo(string)
zur gleichen Zeit deaktivieren.
Andere Tipps
Es ist, weil Namenssuche stoppt, wenn es einen Namen in einem Ihrer Basen findet. Es wird nicht über in anderen Basen suchen. Die Funktion in B Schatten die Funktion in A. Sie haben die Funktion von A im Rahmen von B neu zu erklären, so dass beide Funktionen sichtbar sind von innen B und C:
class A
{
public:
void foo(string s){};
};
class B : public A
{
public:
int foo(int i){};
using A::foo;
};
class C : public B
{
public:
void bar()
{
string s;
foo(s);
}
};
Edit: Die eigentliche Beschreibung der Norm gibt (ab 10.2 / 2):
Die folgenden Schritte definieren das Ergebnis der Namenssuche in einem Klassenbereich, C. Zunächst jede Erklärung für die Namen in der Klasse und in jedem seiner Basisklasse Unterobjekte betrachtet. Einen Mitgliedsnamen f in einem sub- Objekt B verbirgt ein Elementname f in einer A-Unterobjekt, wenn A eine Basisklasse Subobjekt von B. Jede Erklärungen ist die sind so aus der Betrachtung ausgeschlossen versteckt. Jede dieser Erklärungen, die durch eine eingeführte Verwendung Deklaration wird als von jedem Unterobjekt von C sein, die von der Art ist, die Deklarationen enthält, tion durch die Verwendung-declaration.96 bezeichnet) Wenn die resultierende Menge von Deklarationen nicht alle von Unterobjekten sind den gleichen Typs, oder hat das Set ein nicht-statisches Element und umfasst Mitglieder aus unterschiedlichen Unterobjekten, bestehen eine Zweideutigkeit und das Programm schlecht ausgebildet. Ansonsten dieser Satz ist das Ergebnis der Suche.
Es hat den folgenden an einem anderen Ort zu sagen (darüber nur):
Für eine id-Ausdruck [ so etwas wie "foo" ], Namen-Suche beginnt in der Klasse Anwendungsbereich dieser; für eine qualifizierte-ID [ so etwas wie "A :: foo" ist A ein Nested-name-Bezeichner ], Namenssuche im Rahmen des verschachtelten-name-Bezeichner beginnt. Namenssuche erfolgt vor Zugriffskontrolle (3.4, Ziffer 11).
([...] von mir gestellt). Beachten Sie, dass bedeutet, dass selbst wenn Ihr foo in B privat ist, wird die foo in A noch nicht gefunden werden (weil Zugriffskontrolle geschieht später).