Función con el mismo nombre pero con una firma diferente en la clase derivada

Tengo una función con el mismo nombre, pero con una firma diferente en una base y clases derivadas. Cuando trato de usar la función de la clase base en otra clase que hereda del derivado, recibo un error. Vea el siguiente código:

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); } }; 

Recibo el siguiente error del comstackdor gcc:

 In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int) 

Si int foo(int i){}; de la clase B , o si cambio el nombre de foo1 , todo funciona bien.

¿Cuál es el problema con esto?

Las funciones en clases derivadas que no anulan funciones en clases base pero que tienen el mismo nombre ocultan otras funciones del mismo nombre en la clase base.

En general, se considera una mala práctica tener funciones en clases derivadas que tienen el mismo nombre que las funciones en la clase de bajo, que no están destinadas a anular las funciones de la clase base, ya que lo que usted ve no suele ser un comportamiento deseable. Por lo general, es preferible asignar diferentes nombres a diferentes funciones.

Si necesita llamar a la función base, necesitará enfocar la llamada usando A::foo(s) . Tenga en cuenta que esto también desactivaría cualquier mecanismo de función virtual para A::foo(string) al mismo tiempo.

Es porque la búsqueda del nombre se detiene si encuentra un nombre en una de sus bases. No mirará más allá en otras bases. La función en B sombrea la función en A. Debe volver a declarar la función de A en el scope de B, de modo que ambas funciones sean visibles desde B y 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); } }; 

Editar: la descripción real que da el estándar es (desde 10.2 / 2):

Los siguientes pasos definen el resultado de búsqueda de nombre en un ámbito de clase, C. Primero, se considera cada statement para el nombre en la clase y en cada uno de sus sub-objetos de clase base. Un nombre de miembro f en un subobjeto B oculta un nombre de miembro f en un subobjeto A si A es un subobjeto de clase base B. Cualquier statement que esté tan oculta se elimina de la consideración. Cada una de estas declaraciones que fue introducida por una statement using se considera que proviene de cada subobjeto de C que es del tipo que contiene la statement designada por la statement de uso.96) Si el conjunto resultante de declaraciones no es todo desde subobjetos del mismo tipo, o el conjunto tiene un miembro no estático e incluye miembros de distintos subobjetos, existe una ambigüedad y el progtwig está mal formado. De lo contrario, ese conjunto es el resultado de la búsqueda.

Tiene lo siguiente para decir en otro lugar (justo arriba):

Para una expresión-id [ algo así como “foo” ], la búsqueda del nombre comienza en el ámbito de clase de esto; para un id calificado [ algo como “A :: foo”, A es un especificador de nombre nested ], la búsqueda de nombre comienza en el ámbito del especificador de nombre nested. La búsqueda de nombres tiene lugar antes del control de acceso (3.4, cláusula 11).

([…] puesto por mí). Tenga en cuenta que eso significa que incluso si su foo en B es privado, el foo en A aún no se encontrará (porque el control de acceso ocurre más adelante).