Pregunta

Esta pregunta ya tiene una respuesta aquí:

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

No debería el compilador de sobrecarga de la resolución de averiguar el método que 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;
}
¿Fue útil?

Solución

Los dos "sobrecargas" no están en el mismo ámbito.Por defecto, el compilador sólo considera el más pequeño posible ámbito de nombres hasta que encuentra una coincidencia de nombre.Argumento de la coincidencia del hecho después.En el caso de que esto significa que el compilador ve B::DoSomething.Se intenta, entonces, para que coincida con la lista de argumentos, que falla.

Una solución sería bajar la sobrecarga de A en B's alcance:

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

Otros consejos

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

Básicamente, el compilador encuentra una coincidencia de nombre "Haceralgo(int)" en el ámbito de aplicación de la B, ve los parámetros no coinciden, y se detiene con un error.

Se puede superar mediante el uso de la R::Haceralgo 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;
}

No, este comportamiento está presente para asegurarse de que no te pillen heredando desde la lejana clases base por error.

Para conseguir alrededor de él, es necesario decirle al compilador que el método que desea llamar mediante la colocación de un uso de Un::Haceralgo en la clase B.

Ver este artículo para una fácil y rápida introducción de este tipo de comportamiento.

La presencia de un método en una clase derivada se esconde todos los métodos con el mismo nombre (independientemente de los parámetros) en base a clases.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 tarde alguien cambios de clase:

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

ahora, de repente:

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

En otras palabras, si no trabajan como este, un ajenos cambio en una clase en la que no controlan (A), podría silencio afectar cómo funciona el código.

Esto tiene algo que ver con la forma de resolución de nombres funciona.Básicamente, encontramos por primera vez el alcance de la cual sale el nombre y, a continuación, recopilamos todas las sobrecargas para que el nombre de ese ámbito.Sin embargo, el ámbito de aplicación en su caso es de clase B, y en la clase B, B::Haceralgo oculta Un::Haceralgo:

3.3.7 la ocultación de nombres [basic.ámbito de aplicación.ocultar]

...[snip]...

3 En una definición de función miembro, la declaración de un local de nombre esconde la declaración de un miembro de la clase con el mismo nombre;ver basic.scope.class.La declaración de un miembro de una clase derivada (clase.derivados) oculta la declaración de un miembro de una clase base de el mismo nombre;ver clase.miembro.búsqueda.

Debido a la ocultación de nombres, Un::Haceralgo no es ni siquiera considerado para la resolución de sobrecarga

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

Usted puede hacer la función de la clase base visible con el uso de la declaración:

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

Que no sobrecarga!Que se esconde!

Al buscar en el árbol de herencia para la función a utilizar, C++ utiliza el nombre sin argumentos, una vez que se ha encontrado ninguna definición se detiene, a continuación, examina los argumentos.En el ejemplo dado, se detiene en la clase B.Con el fin de ser capaz de hacer lo que está después de, clase B, debe ser definida de la siguiente forma:

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

La función está oculto por la función con el mismo nombre en la subclase (pero con una firma diferente).Usted puede mostrar mediante el uso de la instrucción, como en el uso de Una::DoSomething();

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top