En C++, el orden de búsqueda de nombres está regulado por las reglas de resolución de nombres (name lookup), que tienen en cuenta los ámbitos (scope), el ocultamiento (hiding) y la especificidad de la herencia. Puntos clave:
Resolución de conflictos:
class Base { public: void foo(int) {} }; class Derived : public Base { public: using Base::foo; void foo(double) {} // Versión sobrecargada };
Base::x o Base::foo().Ejemplo de ambigüedad en la herencia diamond:
struct A { int x; }; struct B : virtual A {}; struct C : virtual A {}; struct D : B, C { void test() { x = 42; } // OK: x es único, gracias a virtual };
Si en la clase base se declara un método foo(int), y en la derivada — foo(double), ¿es accesible foo(int) desde un objeto de la clase derivada?
Respuesta: No, el método foo(double) "oculta" todas las versiones sobrecargadas de foo de la clase base. Para acceder a foo(int), es necesario escribir explícitamente using Base::foo o Base::foo en la llamada.
Ejemplo:
class Base { public: void foo(int) { } }; class Derived : public Base { public: void foo(double) {} }; Derived d; d.foo(3); // ¡Error! foo(int) no es visible
Utilizamos:
class Derived : public Base { public: using Base::foo; void foo(double) {} }; d.foo(3); // Todo funciona
Historia
En un proyecto con herencia múltiple, apareció una clase que heredaba de dos bases con métodos foo() idénticos. Los autores no utilizaron herencia virtual, creando dos copias de la clase base — todas las llamadas a foo() se volvían ambiguas, el compilador se negaba a compilar el código. Se resolvió aplicando herencia virtual y especificando explícitamente Base::foo() en la llamada.
Historia
En un motor gráfico, una clase derivada definía su propio draw(), sin hacer using para draw() de la clase base. Al refactorizar el código, se llamaba a la versión incorrecta de draw() — partes de la interfaz dejaban de renderizarse. El error solo se encontró después de un profundo análisis de la estructura de clases.
Historia
Al cambiar a un nuevo compilador, la compilación se volvió imposible debido a la ambigüedad de nombres en la herencia múltiple y virtual. La implementación que anteriormente funcionaba no consideraba diferentes cadenas de incluye, lo que conducía a diferentes conjuntos de nombres en la unidad de traducción.