2015-07-07 10 views
9

Ho pensato di capire l'ereditarietà, le funzioni virtuali e l'overloading delle funzioni, ma ho un caso in cui qualcosa sull'interazione tra queste funzionalità mi sfugge.ereditarietà parziale di set di funzioni virtuali sovraccariche

Supponiamo che io ho una semplice classe di base che contiene una funzione virtuale sovraccarico, e una seconda classe che ne derivano:

class b { 
public: 
    virtual int f() { return 1; } 
    virtual int f(int) { return 2; } 
}; 


class d : public b { 
public: 
    virtual int f(int) { return 3; } 
}; 

Si noti che la classe derivata d override solo una delle funzioni virtuali overload.

posso istanziare un oggetto della classe d e invocare f(int) su di esso, non c'è problema:

d x; 
std::cout << x.f(0) << std::endl; 

Ma quando provo a chiamare la funzione 0-argomento:

std::cout << x.f() << std::endl; 

fallisce! gcc dice "nessuna funzione di matching per la chiamata a 'd :: f()'; i candidati sono: virtual int d :: f (int)". clang dice "troppo pochi argomenti per chiamare la chiamata, l'1 atteso, avere 0, intendevi 'b :: f'?" Anche se d deriva da b che ha un metodo 0-argomento f(), il compilatore lo ignora e prova a chiamare invece il metodo 1-argomento d.

posso risolvere questo problema ripetendo la definizione della funzione 0-argomento nella classe derivata:

class d : public b { 
public: 
    virtual int f() { return 1; } 
    virtual int f(int) { return 3; } 
}; 

Oppure, come suggerito dal messaggio di errore di clang, posso usare una sintassi disambiguazione goofy che non avrei mai hanno indovinato avrebbe funzionato:

std::cout << x.b::f() << std::endl; 

Ma la mia domanda è, quale norma mi rompo, e che cosa è che regola cercando di far rispettare/protezione/difendere? Quello che pensavo stavo cercando di fare qui era esattamente il genere di cosa per cui pensavo che l'ereditarietà fosse.

+0

questa una buona discussione del tema http://stackoverflow.com/questions/1628768/why-does-an-overridden-function-in-the-derived-class -hide-other-overloads-of-the – blade

risposta

7

Questo è noto come nome nascosto.

Quando si dichiara una funzione con lo stesso nome nella classe derivata, tutte le funzioni con lo stesso nome nella base sono nascoste.

Al fine di ottenere l'accesso incondizionato a loro, aggiungere una dichiarazione using nella classe derivata:

class d : public b { 
public: 
    using b::f; 
    virtual int f(int) { return 3; } 
}; 
+1

È negli standard? –

+3

@OthmanBenchekroun [basic.scope.hiding]/1 'Un nome può essere nascosto da una dichiarazione esplicita dello stesso nome in una regione dichiarativa nidificata o classe derivata. – TartanLlama

+0

@OthmanBenchekroun Anche in 13.2 corrispondenza dichiarazione, con lo stesso esempio (o quasi) dato da Steve – marom

2

Qualche spiegazione in aggiunta alla @ risposta di TartanLlama:

Quando il compilatore deve risolvere la chiamata a f, fa tre cose principali, nell'ordine:

  1. Ricerca nome. Prima di fare qualsiasi altra cosa, il compilatore cerca un ambito che abbia almeno un'entità denominata f e crei un elenco di candidati. In questo caso, la ricerca dei nomi guarda prima nell'ambito di d per vedere se c'è almeno un membro chiamato f; in caso contrario, le classi di base e gli spazi dei nomi allegati verranno considerati a turno, uno alla volta, finché non verrà trovato un ambito con almeno un candidato .In questo caso, tuttavia, il primo ambito in cui il compiler del cerca ha già un'entità denominata f e quindi Name lookup stops.

  2. Risoluzione di sovraccarico. Successivamente, il compilatore esegue la risoluzione di sovraccarico per selezionare l'unica corrispondenza migliore tra la lista di candidati. In questo caso, il conteggio dell'argomento non corrisponde, quindi fallisce.

  3. Controllo accessibilità. Infine, il compilatore esegue il controllo dell'accessibilità per determinare se è possibile chiamare la funzione selezionata.

di riferimento per Name lookup