2015-04-13 9 views
16

Ho tre diversi compilatori che sto usando per compilare questo codice. Uno di questi (quello di cui mi fido di meno) avverte che la funzione in Derivato nasconde la funzione in Base. Gli altri compilatori (uno è Visual C++) non avvisano. Visual C++ non avvisa nemmeno se abilito/Wall o/W4.La funzione ha la precedenza sulla funzione di base?

Tendo a credere che questo sia un bug nel compilatore che sta dando un avvertimento, dal momento che compila il codice. Se davvero non ha scavalcato la funzione di base, allora dovrebbe dare un errore quando creo un'istanza del modello derivato.

Qualcuno può confermare come dovrebbe comportarsi?

struct Base 
{ 
    virtual void Func(float f) = 0; 
}; 

template <typename T> 
struct Derived : Base 
{ 
    virtual void Func(T f){} 
}; 

int main() 
{ 
    Derived<float> d; 
    d.Func(0); 
    return 0; 
} 

Quando Derived è istanziato con float ottengo l'avvertimento inaspettato. Quando Derived viene istanziato con int, si verifica un errore, come previsto.

+3

Cosa c'è di sbagliato con un avviso sul codice valido che potrebbe non fare ciò che ci si aspetta? Ad esempio, 'if (b = true)' causerebbe di solito un avvertimento. – chris

+1

Non penso che dovrebbe produrre un avvertimento - non c'è niente di sbagliato nel codice. Non ho mai visto questo tipo di cose (una classe derivata che utilizza la funzione basata su modelli), mi ha fatto riflettere (oou) – pm100

+0

Ho la sensazione che in realtà nasconda la funzione in Base perché se provi a farlo: Base * b = nuovo Derivato (); nel tuo main ti darà l'errore di compilazione: errore C2259: 'Derivato ': impossibile istanziare la classe astratta 1> a causa dei seguenti membri: 1> 'void Base :: Func (float)': è astratto Quindi mi sembra strano. – RedOctober

risposta

7

È in effetti sovrascritto. Si può facilmente convincersi in C++ 11 utilizzando la parola chiave override, che non consentirà il codice per compilare se la funzione non viene sostituito:

struct Base 
{ 
    virtual void Func(float f) = 0; 
    virtual ~Base() = default; // to silence warnings 
}; 

template <typename T> 
struct Derived : Base 
{ 
    void Func(T f) override {} // will fail to compile if not overriding 
}; 

int main() 
{ 
    Derived<float> d; 
    d.Func(0); 
    return 0; 
} 

esempio vivo here.

Si noti che in pre C++ 11, è possibile nascondere accidentalmente una funzione virtual base attraverso cambiando la sua firma in una classe derivata, quindi, anche se si seleziona la funzione derivata virtual il codice viene compilato ancora, ma lo fa non è più polimorfa , vedere un esempio here. Sfortunatamente g ++ non fornisce alcun avvertimento, anche con -Wall -Wextra. Ecco perché override è un modo molto più sicuro di applicare effettivamente l'override vero al momento della compilazione.

4

Non credo che si debba dare un avvertimento.
Questa è la stessa:

struct Derived : Base 
{ 
    virtual void Func(float f) { }; 
}; 

Quando il parametro di modello è float.

Non esiste alcuna occultazione, solo l'implementazione di una funzione astratta.

3

In questo contesto, l'avvertimento che una funzione è nascosta ci fa sapere che una funzione membro nella classe derivata ha lo stesso nome, ma una firma diversa rispetto a una funzione nella classe base. Considerate:

struct Base 
{ 
    void foo(int) {} 
    void bar(int) {} 
}; 

struct Derived: Base 
{ 
    void bar(int, int) {} 
}; 

int main() 
{ 
    Derived d; 
    d.foo(1); 
    d.bar(1); // will not compile: Base::bar is hidden by Derived::bar 
} 

In questo esempio, l'intenzione potrebbe essere stato per aggiungere una funzione aggiuntiva denominata "barra", ma il risultato è che il compilatore si ferma alla ricerca di nuovi ambiti con nome funzioni bar una volta che trova un ambito con un funzione chiamata bar. Quindi bar (int) è nascosto da bar (int, int) (o qualsiasi altra barra con una firma non corrispondente). (O nel caso non virtuale, anche se le funzioni corrispondono.)

In questo codice di Graznarak, Base :: Func è nascosto in qualsiasi situazione in cui Derivato viene istanziato per qualsiasi valore di T che non è float (o float const).

Graznarak chiede il comportamento corretto. Il precedente corretto per il codice generato non è in questione Derived :: Func() è chiamato.

Ma questo lascia la domanda: l'avviso è corretto. Lo standard non ha risposta. Non esprime mai un'opinione sull'opportunità di generare un avviso. Se mettere in guardia o meno su un particolare problema è sempre soggettivo e i compilatori possono distinguersi mostrando un buon giudizio a riguardo.

Quindi il compilatore dovrebbe avvisare di questa situazione? Arguable, il codice come scritto fa ciò che è probabilmente inteso. Ma l'esistenza di un modello implica che verrà istanziata su più di un tipo (altrimenti perché creare un modello) e per qualsiasi altro tipo, occorrerebbe nascondersi. Quindi si potrebbe sostenere che l'avviso dovrebbe essere dato con la creazione del modello derivato. Ma si potrebbe anche sostenere che l'avviso non dovrebbe accadere fino a quando non viene specificata un'istanza di tipo non float.

Discutere per il primo è che l'avviso sarebbe precedente e probabilmente rilevato dal programmatore che scrive il codice problematico. Discutere per il dopo è che finché un tipo non-float viene istanziato, non esiste alcuna situazione sospetta su cui essere avvisati.

Problemi correlati