In C++ wird die Reihenfolge der Namenssuche durch die Regeln der Namensauflösung (Name Lookup) geregelt, die die Gültigkeitsbereiche (Scope), das Verstecken (Hiding) und die Besonderheiten der Vererbung berücksichtigen. Wichtige Punkte:
Konfliktlösung:
class Base { public: void foo(int) {} }; class Derived : public Base { public: using Base::foo; void foo(double) {} // Überladene Version };
Base::x oder Base::foo().Beispiel für Mehrdeutigkeit bei Diamond Inheritance:
struct A { int x; }; struct B : virtual A {}; struct C : virtual A {}; struct D : B, C { void test() { x = 42; } // OK: x ist einmalig, dank virtual };
Wenn in der Basisklasse eine Methode foo(int) deklariert ist und in der abgeleiteten Klasse foo(double), ist foo(int) aus einem Objekt der abgeleiteten Klasse zugänglich?
Antwort: Nein, die Methode foo(double) "versteckt" alle überladenen Versionen von foo in der Basisklasse. Um auf foo(int) zuzugreifen, muss man explizit using Base::foo oder Base::foo im Aufruf schreiben.
Beispiel:
class Base { public: void foo(int) { } }; class Derived : public Base { public: void foo(double) {} }; Derived d; d.foo(3); // Fehler! foo(int) ist nicht sichtbar
Verwenden wir:
class Derived : public Base { public: using Base::foo; void foo(double) {} }; d.foo(3); // Alles funktioniert
Geschichte
In einem Projekt mit Mehrfachvererbung erschien eine Klasse, die von zwei Basisklassen mit gleichen Methoden foo() abgeleitet war. Die Autoren verwendeten keine virtuelle Vererbung, es wurden zwei Kopien der Basisklasse erstellt — alle Aufrufe an foo() wurden mehrdeutig, der Compiler weigerte sich, den Code zu kompilieren. Es wurde durch die Anwendung von virtueller Vererbung und die explizite Angabe von Base::foo() beim Aufruf gelöst.
Geschichte
In einer Grafik-Engine definierte eine abgeleitete Klasse ihre eigene draw(), ohne using für draw() der Basisklasse zu machen. Bei der Umgestaltung des Codes (Refactor) wurde nicht die richtige Version von draw() aufgerufen — Teile der Schnittstelle hörten auf, gerendert zu werden. Der Fehler wurde erst nach einer tiefgehenden Analyse der Klassenstruktur gefunden.
Geschichte
Bei der Umstellung auf einen neuen Compiler wurde die Kompilierung aufgrund der Mehrdeutigkeit von Namen bei Mehrfach- und virtueller Vererbung unmöglich. Die zuvor funktionierende Implementierung berücksichtigte keine unterschiedlichen Include-Ketten, die zu unterschiedlichen Namen in der Übersetzungseinheit führten.