2010-01-13 21 views
6

¿Hay algún problema con anular parcialmente un conjunto de funciones virtuales definidas por una clase base?Problemas con la función de clase parcial anula en C++

Mi compilador proporciona la siguiente advertencia:

overloaded virtual function "MyBaseClass::setValue" is only partially overridden in class "MyDerivedClass". 

Las clases se ven así:

class MyBaseClass 
{ 
public: 
    virtual void setValue(int); 
    virtual void setValue(SpecialType*); 
} 

class MyDerivedClass : public MyBaseClass 
{ 
public: 
    virtual void setValue(int); 
} 

La forma más fácil de deshacerse de esta advertencia es el uso de diferentes nombres para las funciones de base, pero quería saber si había alguna razón convincente para corregir esta advertencia específica. No creo que esto viole el estándar de C++. Creo que es para advertir a un programador que puede haber olvidado implementar el comportamiento para todos los tipos de entrada posibles. En nuestro caso, es intencional excluir algunos de los tipos específicos.

¿Disuadiría de suprimir esta advertencia por completo?

+0

Si está considerando el uso de diferentes nombres para las funciones de base, por todos los medios hacerlo. Eso me sugiere que MyBaseClass :: setValue (int) hace una cosa conceptual diferente de MyDerivedClass :: setValue (int), y eso es malo. Las funciones virtuales deben hacer lo mismo en base y derivadas, o puede obtener errores difíciles de encontrar a partir de cambios menores. –

+0

En mi caso específico, conceptualmente están haciendo lo mismo. El cambio de nombre podría haber sido algo así como setValueFromInt() setValueFromSpecialType() que no se vería tan limpio. Preferiría usar las declaraciones de uso que se describen en una de las respuestas. Actualmente investigando la implementación de ese enfoque. –

Respuesta

13

La anulación para setValue(int) esconde setValue(SpecialType*) de la clase base (ver el C++ FAQ Lite), por lo que si se intenta llamar setValue(new SpecialType()) obtendrá un error.

Esto se puede evitar mediante la adición de una directiva using a la clase derivada que "importaciones" las sobrecargas de la clase base:

class MyDerivedClass : public MyBaseClass 
{ 
public: 
    using MyBaseClass::setValue; 
    virtual void setValue(int); 
}; 
+0

+1 para mostrar realmente cómo NO reescribir las versiones que no le interesan especializarse. –

+0

La instrucción using funciona para mí. Estoy desarrollando para múltiples plataformas. Tengo problemas para que Microsoft Visual Studio 6.0 se queje sobre este problema de código en particular. Incluso con el nivel de advertencia más estricto, no logro que se queje. ¿Alguien con una idea de cómo hacer que este compilador escuche una advertencia? –

6

La advertencia es correcta, se llama "nombre escondido". Una variable del tipo MyDerivedClass no puede llamar al setValue(SpecialType*).


Ahora voy a rasgar descaradamente fuera someone else's blog:

La sobrecarga y el nombre escondido en C++

En una conversación telefónica con Brad anoche, me habló de una extraña problema que ha encontrado en su nuevo trabajo en C++. De acuerdo, probablemente no sea un gran problema para personas con amplia experiencia en C++, pero para aquellos de nosotros que vivimos en mundos de código administrado, esto parecía extraño.

En C++, cuando tiene una clase con un método sobrecargado (función de miembro, como quiera llamarla), y luego amplía y anula ese método, debe anular todos los métodos sobrecargados.

Entiendo el caso en el que ha cambiado la firma de un método en una clase secundaria, lo que invalida la interfaz establecida. En este caso, sin embargo, parece contradictorio, ya que no está cambiando la interfaz, sino que anula selectivamente. Que es diferente.

Por ejemplo:

class FirstClass 
{ 
public: 
     virtual void MethodA (int); 
     virtual void MethodA (int, int); 
}; 

void FirstClass::MethodA (int i) 
{ 
    std::cout << "ONE!!\n"; 
} 

void FirstClass::MethodA (int i, int j) 
{ 
    std::cout << "TWO!!\n"; 
} 

clase simple aquí con dos métodos (o un método sobrecargado). Desea reemplazar la versión de dos parámetros, por lo que de continuar con el siguiente:

class SecondClass : public FirstClass 
{ 
public: 
    void MethodA (int); 
}; 

void SecondClass::MethodA (int i) 
{ 
    std::cout << "THREE!!\n"; 
} 

Ahora, cuando se utiliza una instancia de segunda clase, la mayoría de Java o C# programadores podría suponer que puede llamar:

int main() 
{ 
    SecondClass a; 
    a.MethodA (1); 
    a.MethodA (1, 1); 
} 

sin embargo, la segunda llamada no funcionará, ya que el de dos parámetros MethodA no es visible. Puede obtener un puntero y un up-cast a FirstClass, pero su instancia de SecondClass no hereda los métodos no reemplazados directamente.

0

Está claro que el compilador quiere advertir que: ha creado una subclase que se comporta de manera diferente cuando le da un int, pero no cambió el comportamiento al darle un SpecialType*.

Aunque este podría ser la intención, es muy posible que el comportamiento modificado también sea necesario para las demás funciones virtuales sobrecargadas.

¡Ojalá el compilador me hubiera advertido más, la vez que lo ignoré! Mi método reemplazado resultó compilar y funcionar bien en mi escenario, pero algunos otros escenarios fueron realmente incorrectos debido a que la sobrecarga no se reemplazó.

¡Piense dos veces antes de desactivar esa advertencia!

Si desea que el comportamiento original mantiene, es fácil simplemente llamar a la función de los padres:

class MyDerivedClass : public MyBaseClass { 
    virtual void setValue(int); 
    // explicit: keep original behavior for SpecialType 
    virtual void setValue(SpecialType* p) { MyBaseClass::setValue(p); } 
}; 
+0

Entiendo que las advertencias son importantes y están tratando de advertirme de algo que puede salir mal. La intención de mi pregunta era averiguar por qué la advertencia es importante para el diseñador, y qué peligros puede ocurrir al ignorarla/silenciarla. –

Cuestiones relacionadas