teorico sobrecarga programas practico paso operadores metodos ejemplos dev comandos basicos c++ function overloading resolution

programas - sobrecarga de metodos c++



ResoluciĆ³n de sobrecarga de C++ (9)

Esta pregunta ya tiene una respuesta aquí:

Dado el siguiente ejemplo, ¿por qué tengo que usar explícitamente la declaración b->A::DoSomething() lugar de simplemente b->DoSomething() ?

¿No debería la resolución de sobrecarga del compilador averiguar de qué método estoy hablando?

Estoy usando Microsoft VS 2005. (Nota: el uso de Virtual no ayuda en este caso).

class A { public: int DoSomething() {return 0;}; }; class B : public A { public: int DoSomething(int x) {return 1;}; }; int main() { B* b = new B(); b->A::DoSomething(); //Why this? //b->DoSomething(); //Why not this? (Gives compiler error.) delete b; return 0; }


¡Eso no es una sobrecarga! ¡Eso es OCULTAR!


Al buscar el árbol de herencia para la función a usar, C ++ usa el nombre sin argumentos, una vez que ha encontrado cualquier definición, se detiene y luego examina los argumentos. En el ejemplo dado, se detiene en la clase B. Para poder hacer lo que está buscando, la clase B debe definirse así:

class B : public A { public: using A::DoSomething; int DoSomething(int x) {return 1;}; };


Cuando define una función en una clase derivada, oculta todas las funciones con ese nombre en la clase base. Si la función de clase base es virtual y tiene una firma compatible, la función de clase derivada también anula la función de clase base. Sin embargo, eso no afecta la visibilidad.

Puede hacer visible la función de clase base con una declaración using:

class B : public A { public: int DoSomething(int x) {return 1;}; using A::DoSomething; };


Esto tiene algo que ver con la forma en que funciona la resolución de nombres. Básicamente, primero encontramos el alcance del que proviene el nombre, y luego recopilamos todas las sobrecargas para ese nombre en ese alcance. Sin embargo, el alcance en su caso es clase B, y en clase B, B :: DoSomething oculta A :: DOSomething:

3.3.7 Ocultar nombre [basic.scope.hiding]

...[recorte]...

3 En una definición de función miembro, la declaración de un nombre local oculta la declaración de un miembro de la clase con el mismo nombre; ver basic.scope.class . La declaración de un miembro en una clase derivada ( class.derived ) oculta la declaración de un miembro de una clase base del mismo nombre; vea class.member.lookup .

Debido a la ocultación de nombres, A :: DoSomething ni siquiera se considera para la resolución de sobrecarga


La función está oculta por la función con el mismo nombre en la subclase (pero con una firma diferente). Puede mostrarlo usando la instrucción using, como al usar A :: DoSomething ();


La presencia de un método en una clase derivada oculta todos los métodos con el mismo nombre (independientemente de los parámetros) en las clases base. Esto se hace para evitar problemas como este:

class A {} ; class B :public A { void DoSomething(long) {...} } B b; b.DoSomething(1); // calls B::DoSomething((long)1));

que más tarde alguien cambia la clase A:

class A { void DoSomething(int ) {...} }

ahora de repente:

B b; b.DoSomething(1); // calls A::DoSomething(1);

En otras palabras, si no funcionara así, un cambio no relacionado en una clase que no controlas (A) podría afectar silenciosamente cómo funciona tu código.


La resolución de sobrecarga es una de las partes más feas de C ++

Básicamente, el compilador encuentra un nombre que coincide con "DoSomething (int)" en el alcance de B, ve que los parámetros no coinciden y se detiene con un error.

Se puede superar mediante el uso de A :: DoSomething en la clase B

class A { public: int DoSomething() {return 0;} }; class B : public A { public: using A::DoSomething; int DoSomething(int x) {return 1;} }; int main(int argc, char** argv) { B* b = new B(); // b->A::DoSomething(); // still works, but... b->DoSomething(); // works now too delete b; return 0; }


Las dos "sobrecargas" no están en el mismo alcance. De forma predeterminada, el compilador solo considera el alcance del nombre más pequeño posible hasta que encuentra una coincidencia de nombre. La coincidencia de argumentos se realiza después . En su caso, esto significa que el compilador ve B::DoSomething . Luego intenta hacer coincidir la lista de argumentos, que falla.

Una solución sería reducir la sobrecarga de A en el alcance de B :

class B : public A { public: using A::DoSomething; // … }


No, este comportamiento está presente para garantizar que no te atrapen heredando de clases base distantes por error.

Para evitarlo, debe decirle al compilador a qué método desea llamar colocando un A usando DoSomething en la clase B.

Vea este artículo para una descripción rápida y fácil de este comportamiento.