4.11.2b2 El ámbito de nombres y la sobrecarga de métodos
1 Sinopsis
Se ha indicado ( 4.4.1a) que en C++ no existe el concepto de sobrecarga a través de ámbitos de nombres, y los ámbitos de las clases derivadas no son una excepción a esta regla general. Esto significa que el mecanismo de sobrecarga no funciona para las clases derivadas.
Lo pondremos de manifiesto con un sencillo ejemplo modificando ligeramente el anterior ( 4.11.2b1), de forma que las versiones del método f en la clase-base B y en la derivada D, pudieran ser objeto de sobrecarga:
#include <iostream.h>
class B { // Superclase
public: int f(int i) { cout << "Funcion-Superclase "; return i; }
};
class D : public B { // Subclase
public: float f(float f) { cout << "Funcion-Subclase "; return f+0.1; }
};
int main() { // =================
D d; // instancia de subclase
D* dptr = &d; // puntero-a-subclase señalando objeto
B* bptr = dptr; // puntero-a-superclase señalando objeto de subclase
cout << "d.f(1) " << d.f(1) << endl;
cout << "d.f(1.1) " << d.f(1.1) << endl;
cout << "dptr->f(1) " << dptr->f(1) << endl;
cout << "dptr->f(1.1) " << dptr->f(1.1) << endl;
cout << "bptr->f(1) " << bptr->f(1) << endl;
cout << "bptr->f(1.1) " << bptr->f(1.1) << endl;
}
Salida:
d.f(1) Funcion-Subclase 1.1
d.f(1.1) Funcion-Subclase 1.2
dptr->f(1) Funcion-Subclase 1.1
dptr->f(1.1) Funcion-Subclase 1.2
bptr->f(1) Funcion-Superclase 1
bptr->f(1.1) Funcion-Superclase 1
Comentario
Comprobamos que cualquiera que sea la forma de invocación utilizada, en ningún caso se produce sobrecarga de la función; siempre se accede a la misma versión, dependiendo del subespacio de nombres B o D referenciado.
Nota: si el mecanismo de sobrecarga de funciones hubiese funcionado entre los subespacios de nombres del objeto d, las salidas habrían sido:
d.f(1) Funcion-Superclase 1
d.f(1.1) Funcion-Subclase 1.2
dptr->f(1) Funcion-Superclase 1
dptr->f(1.1) Funcion-Subclase 1.2
bptr->f(1) Funcion-Superclase 1
bptr->f(1.1) Funcion-Subclase 1.2
En estas condiciones cabe preguntarse ¿Que podríamos hacer si realmente necesitamos el funcionamiento del mecanismo de
sobrecarga?. Es decir, si deseamos que, en concordancia con los argumentos de llamada, sea invocada la versión de f
definida en la subclase o de la superclase.
La solución está en utilizar la declaración using ( 4.1.11c). Veámoslo mediante un ejemplo modificando ligeramente el caso anterior (para simplificar el código se han disminuido las salidas).
#include <iostream.h>
class B { // Superclase
public: int f(int i) { cout << "Funcion-Superclase "; return i; }
};
class D : public B { // Subclase
public:
using B::f; // Ok. acceder a las versiones de f en B
float f(float f) { cout << "Funcion-Subclase "; return f+0.1; }
};
int main() { // =================
D d;
D* dptr = &d;
B* bptr = dptr;
cout << dptr->f(1) << endl;
cout << dptr->f(1.0) << endl;
cout << bptr->f(1) << endl;
cout << bptr->f(1.0) << endl;
}
Salida [1]:
Funcion-Superclase 1
Funcion-Subclase 1.1
Funcion-Superclase 1
Funcion-Superclase 1
Comentario
En este caso comprobamos como la sobrecarga ha funcionado en el sentido D B. Cuando accedemos al espacio de nombres D, se invoca correctamente la versión adecuada de f, pero cuando accedemos a B, el espacio D sigue siendo invisible para el mecanismo de sobrecarga.
La representación gráfica idealizada de la situación para la clase derivada D sería la siguiente:
namespace D {
using B::f;
float f(float f);
namespace B {
int f(inf i);
}
}
Cuando se utiliza un identificador como d.f(), o su equivalente dptr->f(), se accede directamente al subespacio D, aunque las versiones interiores de f son accesibles por la declaración using; pero cuando se accede directamente al subespacio B mediante expresiones como bptr->f(), la versión de f en este subespacio sigue ocultando cualquier otro identificador exterior.
Ver otro ejemplo en: "Acceso a subespacios en clases" ( 4.1.11c1)
[1] Aunque los comportamientos descritos en el ejemplo son los Estándar, el compilador Borland C++ 5.5 para Win-32 presenta un error, por lo que los resultados se han obtenido con el compilador MS Visual C++ 6.0 que en este punto se acerca más a la norma.