2015-07-22 15 views
6

Il metodo fun() nella classe derivata è privato. Quando chiamiamo la funzione ptr->fun() tramite il polimorfismo del tempo di esecuzione, è in esecuzione. Ma questo viola la proprietà di incapsulamento della classe derivata.È stata ereditata la funzione amico qui?

#include<iostream> 
using namespace std; 

class Derived; 

class Base { 
private: 
    virtual void fun() { cout << "Base Fun"; } 
friend int main(); 
}; 

class Derived: public Base { 
private: 
    void fun() { cout << "Derived Fun"; } 
}; 

int main() 
{ 
Base *ptr = new Derived; 
ptr->fun(); 
return 0; 
} 

Qualcuno può spiegare per favore cosa sta succedendo?

+0

Gli amici hanno accesso ai membri privati. Dichiari il principale come amico, quindi c'è l'accesso ai membri privati. (perché hai fatto questo è un miracolo per me) – user463035818

+0

@ tobi303, l'amico ha accesso al privato di 'Base' non' Derived' e il 'fun()' che viene chiamato quando il programma viene eseguito è 'fun()' del 'Derived' class .. BTW stavo giocando con i concetti C++, quindi ho trovato questo .. niente di pratico .. – Haris

risposta

2

Prima di tutto, il tuo Derived::fun() è anche virtual, perché se una funzione in una classe derivata ha la stessa dichiarazione di una funzione virtuale nella classe base, la funzione nella classe derivata ottiene automaticamente virtual, anche se questo non era esplicitamente specificato.

In secondo luogo, è completamente OK accedere alle funzioni virtuali private tramite funzioni intermedie pubbliche dalla classe base, vedere, ad esempio, this answer e i relativi collegamenti, in particolare Virtuality by Herb Sutter. Un codice di esempio potrebbe essere come

#include<iostream> 
using namespace std; 

class Derived; 

class Base { 
private: 
    virtual void fun() { cout << "Base Fun"; } 
public: 
    void funInt() { fun(); } 
}; 

class Derived: public Base { 
private: 
    virtual void fun() { cout << "Derived Fun"; } 
}; 

int main() 
{ 
Base *ptr = new Derived; 
ptr->funInt(); 
return 0; 
} 

Allora, che cosa succede nel tuo caso, credo, è una situazione simile: il main è autorizzato ad accedere ptr->fun(), ma a causa di questo virtualità fun() sembra essere Derived::fun().

UPD: espansione su un commento

Ma non lo fa questo suono un po 'allarmante ..Voglio dire, tutte le funzioni che derivano dalla classe base, avranno i loro membri privati ​​ accessibile all'amico funzioni della classe base

No, non tutte le funzioni del Derived saranno accessibili agli amici di Base, ma solo quelli che possono essere accessibili tramite il puntatore Base. Ad esempio:

class Base { 
    virtual void fun(); 
    friend int main(); 
} 
class Derived: public Base { 
    virtual void fun(); 
    virtual void foo(); 
    void bar(); 
} 

solo Derived::fun() è accessibile dalla principale:

int main() { 
    Derived *ptr = new Derived; 
    Base* baseptr = ptr; 
    baseptr->fun(); // ok, calls Derived::fun() 
    baseptr->foo(); // error, no such function in Base 
    ptr->foo(); // error, foo is private 
    return 0; 
} 

noti che virtual funzione sono intenzionalmente estensibile e ogni override virtual funzione Derived significa che tale funzione può essere chiamata tramite Base puntatore; questo è lo scopo principale delle funzioni virtual. Se Derived ha la sua funzione di override private, è comunque necessario tenere presente che è possibile accedere alla funzione tramite il puntatore Base, poiché questa è l'idea principale dietro le funzioni virtual.

+0

ook. Ma questo non suona un po 'allarmante .. Voglio dire, tutte le funzioni che derivano dalla classe 'Base', avranno i loro membri privati ​​accessibili alle funzioni di amico della classe' Base'. – Haris

+0

@haris, no! Solo le funzioni 'virtuali' che sono già presenti in' Base'! Espanderò la risposta tra un minuto. – Petr

+1

@haris, ha ampliato la risposta – Petr

0

Questo sta accadendo perché hai dichiarato fun come virtuale. In fase di esecuzione quando viene cercata la vtable, trova la voce per Derived::fun() e quindi salta all'indirizzo.

Tuttavia, le funzioni di amicizia non vengono ereditate, è possibile verificarne l'utilizzo.

class Base { 
private: 
    virtual void fun() { cout << "Base Fun"; } 
    friend int main(); 
    int z = 20; 
}; 

class Derived : public Base { 
private: 
    void fun() { cout << "Derived Fun"; } 
    int m = 10; 
}; 

int main() 
{ 
    Base *ptr = new Derived; 
    ptr->z = 10; //Accepted 
    ptr->m = 5; //error 
    return 0; 
} 

membro Qui privata di Derivedm non è accessibile al principale.

+0

non ti ho capito, il programma sta accedendo alla funzione privata della classe derivata dal' main() ' funzione .. come fa la funzione 'fun()' in effetti virtuali di classe Base che .. – Haris

+0

@Nishant dubito che i vtable funzionino in questo modo ... vedi questa descrizione http://imgur.com/6e23Roa – Haris

+0

@DenisZaikin sì, ovviamente sarà "Base Fun", perché ptr sta puntando all'oggetto di derivato, che ha subobject di base. – Nishant

1

Friend le funzioni non partecipano mai all'ereditarietà.

Che cosa sta succedendo qui?
Quando il metodo virtuale è definito nella classe Base, viene creata una tabella virtuale che contiene l'indirizzo del metodo fun della classe Base. E poiché la classe Derived lo eredita, il VTABLE contiene anche l'indirizzo del metodo della classe . Ora, dal momento che main è la funzione friend della classe Base, il compilatore consente l'accesso dei suoi membri al metodo main indipendentemente dal loro specificatore di accesso. Quindi, main ottiene l'indirizzo di Derived::fun e classe fun viene richiamato in fase di esecuzione.

Problemi correlati