2012-07-12 18 views
12
#include <iostream> 
struct B1 
{ 
    virtual void method()=0; 
    virtual ~B1(){} 
}; 

struct B2 
{ 
    virtual void method()=0; 
    virtual ~B2(){} 
}; 

struct D: B1, B2 
{ 
    virtual void method() 
    { 
     std::cout << "D::method\n"; 
    }; 
}; 

int main(int argc,char *argv[]) 
{ 
    D d; 
    B1 &b1=d; 
    B2 &b2=d; 
    b1.method(); 
    b2.method(); 
    return 0; 
} 

Nota: B1 y B2 no comparten una interfaz común.Sobrescribe la función virtual de las clases base, que no comparten una interfaz común

¿Es esto legal? En caso afirmativo, ¿en qué estándar? C++ 98/03/11?

Ambos, msvc y gcc lo han compilado correctamente.

Anteriormente pensé que tenía que usar una interfaz común para ese caso (posible herencia virtual).

¿Tal situación tiene algún nombre especial?

¿Cómo funciona en detalles, por favor? Tal vez algunas referencias ISO?

+0

Si explica lo que lo lleva a pensar que es un caso especial, es posible que alguien encuentre una buena explicación. –

+0

Porque en ese caso, espero tener dos funciones virtuales heredadas * independientes * distintas en D: B1 :: method y B2 :: method. – John

Respuesta

7

Su código está bien formado: void D::method() anula tanto void B1::method() y void B2::method().

La especificación establece (C++ 11 §10.3/2):

Si una función miembro virtual vf se declara en una clase de Base y en una clase de Derived, derivada directa o indirectamente de Base, una función miembro vf con el mismo nombre, el parámetro de tipo lista , cv-qualification, y ref-qualifier (o la ausencia de la misma) como Base::vf se declara, entonces Derived::vf también es virtual (esté o no declarado) e invalida Base::vf.

B1 declara una función de miembro virtual void B1::method(). La clase D se deriva de B1 y también declara una función miembro con el mismo nombre (method), la misma lista de parámetros (sin parámetros), la misma calificación cv (sin calificación) y el mismo calificador ref (sin calificación).

Por lo tanto, void D::method() reemplaza void B1::method().

La misma lógica se aplica para void B2::method() (justo sustituir B2 para B1 en la explicación anterior), de modo void D::method() anulaciones ambos void B1::method() y void B2::method().

+0

Gracias, eso suena tan cierto. Encontré elementos similares en C++ 03 y C++ 98. Pero, tengo curiosidad, ¿hay algunas adiciones estándar a esa situación? Tal vez algunas notas especiales para la herencia múltiple? – John

+0

Aparte del "y el calificador de ref", esperaría que la especificación fuera la misma en C++ 98 y C++ 03. –

+0

Genial, eso es bueno saberlo. Por cierto, solo * utilizando * method() * sin * overriding solo está permitido para D si se accede a D a través de referencias/punteros de clase base. Comparar http://stackoverflow.com/questions/3310910/method-resolution-order-in-c/3310948#3310948 –

1

afaik Esto es legal en todos los estándares. No estoy seguro si tiene su propio nombre especial, pero es similar al diamond problem.

si invalida el "método virtual void()" en D, entonces anula el método en B1 y B2.

Editar:

a anwser razón por la que no tiene "dos independed diferente heredó las funciones virtuales en D: B1 y B2 :: método :: Método":

al redefinir un método, can solo puede especificar el nombre de la función, el tipo de retorno y los parámetros, pero no puede agregar detalles de la firma acerca de cuál hereda al anular.

imaginar que sería posible, entonces podría ser algo como esto:

struct D: B1, B2 
{ 
    virtual void B1::method() 
    { 
     std::cout << "D::method\n"; 
    }; 
    virtual void B2::method() 
    { 
     std::cout << "D::method\n"; 
    }; 
}; 

pero ver esto, ya se puede decir que no existe la posibilidad de tener algo así, porque al llamar

objectD.method() 

no puede especificar a cuál llama. por lo tanto, incluso si hubiera una forma de sobrecargar ambos, aún existe el problema de distinguir en la llamada a la función.

EDITAR: "no puedo especificar a cuál llama." hace referencia a, no puede especificar si desea invocar una sobrecarga de clase D del método B2 :: o el método B2 en sí mismo. Método objectD.B2 :: método siempre invocar el B2 (no sobrecargado) (que en este caso no se compilará como B2 no tiene ninguna aplicación)

+0

Gracias, entendí esto. Me gustaría saber más detalles, porque es un poco sorprendente para mí. – John

+0

@James McNellis no sería posible solo dentro de un miembro de la clase? void B1method() {B1 :: method}? – cppanda

+1

revise esto http://ideone.com/jdsMI – John

Cuestiones relacionadas