2011-01-29 13 views
24

¿Cuál es la lógica detrás de hiding rule en C++?C++: justificación detrás de la regla de ocultación

class A { void f(int); } 
class B : public A { void f(double); } // B::f(int) is hidden 
  • Si se trata de una característica significativa Creo que también debería ser posible ocultar las funciones sin la definición de 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 simplifica el trabajo compiladores, ya que los compiladores deben ser capaces de todos modos unhide funciones cuando se utiliza explícitamente el using Directiva:

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

Así que, ¿cómo es que no hay una regla de ocultamiento?


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

+0

Si bien la decisión no se basó en facilitar la vida de los escritores del compilador, el argumento que el compilador todavía necesita mostrar no es válido. Cuando el compilador analiza la clase con el uso, trae todos los 'A :: f' a la representación en memoria de la clase. Cuando intenta resolver una llamada, solo necesita volver tan lejos como sea necesario hasta que encuentre la primera aparición del identificador. No es necesario volver atrás, posiblemente, en varias rutas para poner todos los posibles identificadores en el alcance. Lo mismo ocurre con el hecho de que un método miembro ocultará una función de nivel de espacio de nombres ... –

+0

AFAIK, * ocultarse sin definir nuevas funciones * es posible en C++ 11 mediante '= delete'. – Walter

+0

Existe un mecanismo para ocultar las funciones de la clase base. Utilice 'clase A: protegido B {...};' en lugar de 'público'. Perdón por vencer a un caballo muerto. –

Respuesta

10

Es una pregunta peliaguda, pero aparentemente la idea es que esta característica oculta ayuda a evitar errores sutiles cuando se realizan cambios en una clase base (que de otra forma podría "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, así que no creo que entiendo al 100% esta explicación.

Acepto 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 here ...

9

No sé la razón original, pero ya no ocultar o disimular son casi igual de malas elecciones WRT. a las funciones, supongo que la razón es tener reglas uniformes: lo mismo que para los nombres definidos en los alcances de llaves rizadas anidadas.

la ocultación te ayuda de alguna manera.

agregar un método a una clase base no afectará de forma predeterminada la resolución de sobrecarga para una clase derivada.

y no se topa con la resolución de sobrecarga por algún error dirigiendo su llamada con el argumento false, a un método de clase base con el argumento formal void*. tales cosas. .

aplausos & HTH,

+0

¡Estoy desconcertado de que en realidad seas el único que habló sobre la coherencia con las funciones de ocultación de otros ámbitos! Sigo pensando que es principalmente una cuestión de evitar sorpresas. –

7

Estoy seguro de que he visto en este caso ofrecida por un pez gordo de C++, pero no estoy seguro:

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, añadir void f(int);-Base, y el significado de cambios principales: llama a Base::f porque int es una mejor coincidencia para char - es una promoción entera en lugar de una conversión estándar.

No es claro si ese cambio a la base sería realmente destinados mediante el programador para coger llamadas con char, por lo que requiere using ser explícito significa que el comportamiento por defecto es que el cambio no afecta al 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 "ocultar" porque no hay un caso comparable para ocultando "f" de la Base cuando no está sobrecargado en Derivado.

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

-2

Probablemente, el motivo es la especialización de plantillas. Os pongo 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 plantilla de clase B tiene un método f(), pero hasta que no se crea una instancia de la clase B no se sabe la firma. Entonces la llamada this->f() es en cualquier momento "legal". Tanto GCC como CLang no informan el error hasta que crea la instancia. Pero cuando llamas al método g() en una instancia B<1>, indican el error. Entonces, la regla de ocultamiento es más simple para verificar si su código es válido.

Informo la última parte del código utilizado 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; 
} 
+3

Excepto que, en su ejemplo, no hay absolutamente nada en la clase de plantilla B que oculte el método f que se declara en la clase de plantilla A ... El error no proviene del hecho de que f (vacío) está oculto en B <1> (¿por qué sería más oculto en B <1> que en B <0> ya que no hay especialización).Tu problema es * solo * que f (vacío) no está declarado en absoluto en A <1>: no hay nada que esconder. –

3

Otra razón para ocultar función miembro de clase base (con el mismo nombre pero diferentes firmas) podría ser debido a la ambigüedad causada por parámetros opcionales. Consideremos 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 había convertido en oculto, que no sería posible para el compilador para decidir si se debe llamar A::foo o B::foo ya que la siguiente línea coincide con la firma de ambos:

foo(a); 
Cuestiones relacionadas