2010-08-31 18 views
29
#include<iostream> 

using namespace std; 
class base 
{ 
public: 
    virtual void add() { 
     cout << "hi"; 
    } 
}; 

class derived : public base 
{ 
private: 
    void add() { 
     cout << "bye"; 
    } 
}; 

int main() 
{ 
    base *ptr; 
    ptr = new derived; 
    ptr->add(); 
    return 0; 
} 

uscita è byePerché è possibile accedere a una funzione membro privata derivata tramite un puntatore di classe base a un oggetto derivato?

Non ho un problema con come questo è implementato. Capisco che tu usi vtables e che il vtable di derivato contenga l'indirizzo della nuova funzione add(). Ma add() è privato non dovrebbe generare un errore nel compilatore quando provo ad accedervi al di fuori della classe? In qualche modo non sembra giusto.

+4

Gli identificatori di override e accesso sono concetti ortogonali. – sbi

+0

i vtables sono un dettaglio di implementazione. –

risposta

32

add() è solo privata in derived, ma il tipo statico quello che hai è base* - in tal modo si applicano le restrizioni di accesso di base.
In generale non si può nemmeno sapere in fase di compilazione quale sarà il tipo dinamico di un puntatore a base, potrebbe ad es. cambia in base all'input dell'utente.

Questo è per C++ 03 §11.6:

Le regole di accesso (clausola 11) per una funzione virtuale sono determinati dalla sua dichiarazione e non sono influenzati dalle norme per una funzione che successivamente lo sovrascrive.
[...] L'accesso viene verificato nel punto di chiamata utilizzando il tipo dell'espressione utilizzata per indicare l'oggetto per il quale viene chiamata la funzione membro [...]. L'accesso della funzione membro nella classe in cui è stato definito [...] in generale non è noto.

+0

+1 - Grazie per il commento chiarificatore sulla mia risposta. –

+0

@Georg Fritzsche Può darmi un link di C++ 03 da dove hai copiato questo link. Ho cercato su google, ma non ho trovato, voglio studiare C++ –

+0

@Jai: ["Dove trovo gli attuali documenti standard C o C++?"] (Http://stackoverflow.com/questions/81656/where-do-i-find -the-current-c-or-c-standard-documents) –

5

Per aggiungere un po 'per la risposta di Georg:

Ricordate che il compilatore non ha alcun controllo e non può garantire nulla di classi derivate. Ad esempio, potrei spedire il mio tipo in una libreria e derivarne da esso in un programma completamente nuovo. In che modo il compilatore della biblioteca dovrebbe sapere che il derivato potrebbe avere un identificatore di accesso diverso? Il tipo derivato non esisteva quando la libreria è stata compilata.

Per supportare questo, il compilatore dovrebbe conoscere gli specificatori di accesso in fase di esecuzione e generare un'eccezione se si è tentato di accedere a un membro privato.

10

I modificatori di accesso, ad esempio public, private e protected vengono applicati solo durante la compilazione. Quando si chiama la funzione attraverso un puntatore alla classe base, il compilatore non sa che il puntatore punta a un'istanza della classe derivata. Secondo le regole che il compilatore può dedurre da questa espressione, questa chiamata è valida.

Di solito è un errore semantico per ridurre la visibilità di un membro in una classe derivata. I linguaggi di programmazione moderni come Java e C# si rifiutano di compilare tale codice, poiché un membro visibile nella classe base è sempre accessibile nella classe derivata tramite un puntatore di base.

+1

+1 Risposta migliore. –

Problemi correlati