2009-10-27 18 views
179

Considere el código:¿Por qué una función anulada en la clase derivada oculta otras sobrecargas de la clase base?

#include <stdio.h> 

class Base { 
public: 
    virtual void gogo(int a){ 
     printf(" Base :: gogo (int) \n"); 
    }; 

    virtual void gogo(int* a){ 
     printf(" Base :: gogo (int*) \n"); 
    }; 
}; 

class Derived : public Base{ 
public: 
    virtual void gogo(int* a){ 
     printf(" Derived :: gogo (int*) \n"); 
    }; 
}; 

int main(){ 
    Derived obj; 
    obj.gogo(7); 
} 

dio este mensaje:

 
>g++ -pedantic -Os test.cpp -o test 
test.cpp: In function `int main()': 
test.cpp:31: error: no matching function for call to `Derived::gogo(int)' 
test.cpp:21: note: candidates are: virtual void Derived::gogo(int*) 
test.cpp:33:2: warning: no newline at end of file 
>Exit code: 1 

En este caso, la función de la clase derivada está eclipsando todas las funciones del mismo nombre (no firma) en la clase base. De alguna manera, este comportamiento de C++ no se ve bien. No es polimórfico.

+6

pregunta brillante, descubrí esto recientemente también –

+0

Duplicado: http://stackoverflow.com/questions/411103/function-with-same-name-but-different-signature-in-derived-class – psychotik

+6

Pase por el siguiente enlace y encontrarás tu respuesta. [El artículo] (http://www.research.att.com/~bs/bs_faq2.html#overloadderived) fue escrito por Bjarne Stroustrup. – Ashish

Respuesta

344

A juzgar por la redacción de su pregunta (utilizó la palabra "ocultar"), ya sabe lo que está sucediendo aquí. El fenómeno se llama "ocultamiento de nombre". Por alguna razón, cada vez que alguien pregunta por qué se esconde el nombre, las personas que responden dicen que esto se llama "nombre oculto" y explican cómo funciona (que probablemente ya conozca), o explican cómo anularlo (sobre el cual nunca preguntaste), pero a nadie parece importarle abordar la pregunta real de "por qué".

La decisión, la lógica detrás del nombre oculto, es decir qué que en realidad fue diseñado en C++, es evitar cierta contrario a la intuición, imprevisto y el comportamiento potencialmente peligroso que podría tener lugar si el conjunto heredado de funciones sobrecargadas se les permitió mezclar con el conjunto actual de sobrecargas en la clase dada. Probablemente sepa que en C++ la resolución de sobrecarga funciona al elegir la mejor función del conjunto de candidatos. Esto se hace al hacer coincidir los tipos de argumentos con los tipos de parámetros. Las reglas de coincidencia pueden ser complicadas a veces y, a menudo, pueden dar lugar a resultados que un usuario no preparado podría percibir como ilógicos. Agregar nuevas funciones a un conjunto de otras ya existentes puede dar lugar a un cambio bastante drástico en los resultados de resolución de sobrecarga.

Por ejemplo, supongamos que la clase base B tiene una función miembro foo que toma un parámetro de tipo void *, y todas las llamadas a foo(NULL) se resuelven a B::foo(void *).Digamos que no hay ningún nombre oculto y este B::foo(void *) es visible en muchas clases diferentes que descienden de B. Sin embargo, digamos que en algún descendiente [indirecto, remoto] D de la clase B se define una función foo(int). Ahora, sin nombre oculto, D tiene tanto foo(void *) como foo(int) visibles y participando en la resolución de sobrecarga. ¿Qué función resolverán las llamadas a foo(NULL), si se realiza a través de un objeto de tipo D? Se resolverán en D::foo(int), ya que int es una mejor coincidencia para el cero integral (es decir, NULL) que cualquier tipo de puntero. Por lo tanto, en toda la jerarquía, las llamadas a foo(NULL) se resuelven en una función, mientras que en D (y menos) se resuelven de repente a otra.

Este comportamiento se consideró indeseable cuando se diseñó el idioma. Como mejor enfoque, se decidió seguir la especificación de "ocultamiento de nombre", lo que significa que cada clase comienza con una "hoja limpia" con respecto al nombre de cada método que declara. Para anular este comportamiento, se requiere una acción explícita del usuario: originalmente una redeclaración de método (s) heredado (actualmente en desuso), ahora un uso explícito de use-declaration.

Como correctamente observó en su publicación original (me refiero a la observación "No polimórfico"), este comportamiento puede ser visto como una violación de la relación IS-A entre las clases. Esto es cierto, pero aparentemente en aquel entonces se decidió que, al final, esconderse sería un mal menor.

+17

Sí, esta es una respuesta real a la pregunta. Gracias. Yo también tenía curiosidad. – Omnifarious

+4

¡Excelente respuesta! Además, como cuestión práctica, la compilación probablemente sería mucho más lenta si la búsqueda del nombre tuviera que llegar a la cima cada vez. –

+0

~~ Cool answer ~~ – fizzbuzz

13

Esto es "Por diseño". En C++ la resolución de sobrecarga para este tipo de método funciona de la siguiente manera.

  • Comenzando por el tipo de la referencia y después de ir al tipo base, encontrar el primer tipo que tiene un método denominado "Gogo"
  • Teniendo en cuenta sólo los métodos llamados "gogo" en ese tipo de encontrar una sobrecarga de coincidencia

Dado que Derived no tiene una función coincidente llamada "gogo", la resolución de sobrecarga falla.

+4

desafortunado pero cierto. –

37

Las reglas de resolución de nombres indican que la búsqueda de nombre se detiene en el primer ámbito en el que se encuentra un nombre coincidente. En ese punto, las reglas de resolución de sobrecarga se activan para encontrar la mejor coincidencia de funciones disponibles.

En este caso, gogo(int*) se encuentra (solo) en el alcance de la clase Derivada, y como no hay una conversión estándar de int a int *, la búsqueda falla.

La solución es traer las declaraciones de bases en medio de una declaración using en la clase derivada:

using Base::gogo; 

... permitiría a las reglas de búsqueda de nombres para encontrar todos los candidatos y por lo tanto la resolución de sobrecarga podría proceder de la lo esperabas

+3

¿Pero por qué? ????? –

+8

OP: "¿Por qué una función anulada en la clase derivada oculta otras sobrecargas de la clase base?" Esta respuesta: "Porque lo hace". –

Cuestiones relacionadas