C++: justificación detrás de la regla de ocultación


¿Cuál es la razón detrás de la regla de ocultación en C++?

class A { void f(int); }
class B : public A { void f(double); } // B::f(int) is hidden
  • Si es una característica significativa creo que también debería ser posible ocultar funciones sin definir nuevas funciones con el mismo nombre: algo como esto:

    class B : public A { hide void f(double); }
    

    Pero esto no es posible.

  • No creo que simplifique el trabajo de los compiladores, ya que de todos modos los compiladores deben ser capaces de mostrar funciones cuando se utiliza explícitamente el using directiva:

    class B : public A { using A::f; void f(double); } // B::f(int) NOT hidden
    

Entonces, ¿cómo es que hay una regla de ocultamiento?


Hum, las tres respuestas parecen ser buenas, y muestran diferentes razones para la regla de ocultamiento. No estoy seguro de qué respuesta debería aceptar.

Author: peoro, 2011-01-29

5 answers

Es una pregunta peluda, pero aparentemente la idea es que esta característica de ocultación ayuda a evitar errores sutiles al hacer cambios en una clase base (que de otra manera podrían "robar" llamadas que antes habrían sido manejadas por la clase derivada). Todavía un cambio en una clase base puede influir en el resultado de la compilación de clases derivadas, por lo que no creo entender 100% esta explicación.

Estoy de acuerdo en que este tema se discute con tanta frecuencia que probablemente el ocultamiento en realidad aumenta la cantidad de "sorpresas" en los programadores de C++.

Una discusión detallada sobre este tema se puede encontrar aquí...

 10
Author: 6502,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-24 15:46:45

No conozco el razonamiento original, pero como hide o not hide son elecciones igualmente malas wrt. para las funciones, supongo que la razón es tener reglas uniformes: las mismas que para los nombres definidos en ámbitos de llaves anidadas.

El ocultamiento te ayuda de alguna manera.

Agregar un método a una clase base por defecto no afectará la resolución de sobrecarga para una clase derivada.

Y no se encuentra en conflicto con la resolución de sobrecarga por algún percance dirigiendo su llamada con say argument false, a un método de clase base con argumento formal void*. esas cosas.

Salud y hth.,

 9
Author: Cheers and hth. - Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-29 15:03:34

Estoy seguro de que he visto este caso ofrecido por un pez gordo de C++, no estoy seguro de cuál:

struct Base {
    void f(const Base&);
};

struct Derived : Base {
    using Base::f;
    void f(double);
};

int main() {
    Derived d;
    d.f('a'); // calls Derived::f
}

Ahora, agregue void f(int); a Base, y el significado de los cambios principales - llama a Base::f porque int es una mejor coincidencia para char - es una promoción de enteros en lugar de una conversión estándar.

No está claro si ese cambio a la base realmente sería destinado por el programador para capturar llamadas con char, por lo que requerir using para ser explícito significa que el comportamiento predeterminado es que el cambio no afecta el código de llamada. Creo que es una llamada marginal, pero creo que el comité decidió que las clases base en C++ eran lo suficientemente frágiles como son, sin esto también: -)

No hay necesidad de una palabra clave "hide" porque no hay un caso comparable para ocultar "f" de la Base cuando no está sobrecargada en Derivada.

Por cierto, he elegido los tipos, y char es deliberadamente incongruente. Puede obtener casos más sutiles con int vs unsigned int en lugar de int vs char.

 7
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-29 16:44:20

Otra razón para ocultar la función miembro de la clase base (con el mismo nombre pero diferentes firmas) podría deberse a la ambigüedad causada por parámetros opcionales. Considere el siguiente ejemplo:

#include <stdio.h>

class A
{
public:
    int foo(int a, int b=0)
    {
        printf("in A : %d, %d\n", a, b);
    }
};

class B : public A
{
public:
    int foo(int a)
    {
        printf("in B : %d\n", a);
        foo(a); //B:foo(a) will be called unless we explicitly call A:foo(a)
        foo(a, 1); // compile error: no matching function for call to B:foo(int&, int)
    }
};


int main()
{
    B b;
    b.foo(10);
    return 0;
}

Si el método foo en la clase base no se hubiera ocultado, no sería posible para el compilador decidir si se debe llamar a A::foo o B::foo ya que la siguiente línea coincide con ambas firmas:

foo(a);
 3
Author: Meysam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-16 12:35:24

Probablemente, la razón es la especialización de plantillas. Les doy un ejemplo:

template <int D> struct A { void f() };

template <> struct A<1> { void f(int) };

template <int D>
struct B: A<D>
{
  void g() { this->f(); }
};

La clase B de la plantilla tiene un método f(), pero hasta que no cree una instancia de la clase B no conoce la firma. Así que la llamada this->f() es en cualquier momento "legal". Tanto GCC como CLang no informan de errores hasta que crea la instancia. Pero cuando llamas al método g() en una instancia B<1> indican el error. Por lo tanto, la regla de ocultación se mantiene más simple para verificar si su código es válido.

I reporta la última parte del código usado en mi ejemplo.

int main (int argc, char const *argv[])
{
  B<0> b0; /* valid */
  B<1> b1; /* valid */

  b0.g(); /* valid */
  b1.g(); /* error: no matching function for call to ‘B<1>::f()’ */

  return 0;
}
 -2
Author: mattia.penati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-31 16:44:28