2012-07-12 11 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 e B2 non condividono l'interfaccia comune.Ignora la funzione virtuale delle classi base, che non condividono l'interfaccia comune

È legale? Se sì - in quale standard? C++ 98/03/11?

Entrambi, msvc e gcc lo hanno compilato OK.

In precedenza ho pensato, che devo utilizzare un'interfaccia comune per tale caso (possibile ereditarietà virtuale).

Questa situazione ha un nome speciale?

Come funziona nei dettagli, per favore? Forse alcuni riferimenti ISO?

+0

Se spieghi cosa ti porta a pensare che sia un caso speciale, qualcuno potrebbe trovare una buona spiegazione. –

+0

Perché in questo caso, mi aspetto di avere due diverse funzioni virtuali ereditate * indipendenti * in D: B1 :: method e B2 :: method. – John

risposta

7

il codice sia ben formata: void D::method() override sia void B1::method() e void B2::method().

Gli stati delle specifiche (C++ 11 §10.3/2):

Se una funzione membro virtual vf è dichiarato in una classe Base e in una classe Derived, derivata direttamente o indirettamente da Base, una funzione membro vf con lo stesso nome, il parametro di tipo-list , qualifica cv e qualificazione ref (o assenza dello stesso) come Base::vf viene dichiarata, quindi Derived::vf è anche virtuale (indipendentemente dal fatto che sia dichiarata o meno) e sostituisce Base::vf.

B1 dichiara una funzione membro virtuale void B1::method(). La classe D deriva da B1 e dichiara anche una funzione membro con lo stesso nome (method), la stessa lista di parametri (nessun parametro), la stessa qualifica di cv (nessuna qualifica) e lo stesso qualificatore di ref (nessuna qualifica).

Pertanto, void D::method() ha la precedenza su void B1::method().

La stessa logica vale per void B2::method() (basta sostituire B2 per B1 nella spiegazione di cui sopra), quindi void D::method() sostituzioni sia void B1::method() e void B2::method().

+0

Grazie, sembra vero. Ho trovato elementi simili su C++ 03 e C++ 98. Ma, sono curioso, ci sono alcune aggiunte standard a quella situazione? Forse alcune note speciali per l'ereditarietà multipla? – John

+0

Oltre al "e ref-qualificatore", mi aspetto che le specifiche siano le stesse in C++ 98 e C++ 03. –

+0

Grande, è bello saperlo. A proposito, solo * usando * method() * senza * override è consentito solo per D se D è accessibile tramite riferimenti/puntatori di classe base. Confronta http://stackoverflow.com/questions/3310910/method-resolution-order-in-c/3310948#3310948 –

1

questo è legale in ogni standard. non sono sicuro che abbia il suo nome speciale, ma è simile allo diamond problem.

se si esegue l'override di "virtual void method()" in D, quindi si esegue l'override di entrambi i metodi in B1 e B2.

Edit:

a anwser perché non si dispone di "due diversi indipendenti sui ereditato le funzioni virtuali in D: B1 e B2 :: metodo :: Metodo":

quando l'override un metodo, può solo specificare il nome della funzione, il tipo e i parametri di restituzione, ma non è possibile aggiungere dettagli della firma su quale ereditare da quando si esegue l'override.

immaginare che sarebbe stato possibile, allora potrebbe essere simile a questa:

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

ma vedendo questo, si può già dire che non v'è alcuna possibilità di avere una cosa del genere, perché quando si chiama

objectD.method() 

non è possibile specificare quale si sta chiamando. quindi anche se c'era un modo per sovraccaricarli entrambi, c'è ancora il problema di distinguere sulla chiamata di funzione.

MODIFICA: "non è possibile specificare quale si sta chiamando." fa riferimento a, non è possibile specificare se si desidera chiamare un sovraccarico di classe D del metodo B2 :: o il metodo B2 stesso. Metodo objectD.B2 :: metodo sarà sempre invocare il B2 (non sovraccaricato) (che in questo caso non verrà compilato come B2 non ha alcuna implementazione)

+0

Grazie, ho capito questo. Mi piacerebbe sapere qualche altro dettaglio, perché è un po 'sorprendente per me. – John

+0

@James McNellis non sarebbe possibile solo all'interno di un membro della classe? void B1method() {B1 :: method}? – cppanda

+1

controlla questo http://ideone.com/jdsMI – John