2015-07-22 8 views
6

Die Methode fun() in der Klasse Derived ist privat. Wenn wir die Funktion ptr->fun() durch Laufzeitpolymorphismus aufrufen, wird sie ausgeführt. Dies verletzt jedoch die Kapselungseigenschaft der abgeleiteten Klasse.Wird die Freund-Funktion hier vererbt?

#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; 
} 

Kann jemand bitte erklären, was passiert ist?

+0

Freunde haben Zugang zu privaten Mitgliedern. Du deklarierst den Main als Freund, also hast du Zugriff auf private Mitglieder. (Warum hast du das getan ist ein Wunder für mich) – user463035818

+0

@ tobi303, Freund hat Zugriff auf private von 'Base' nicht' Derived' und die 'fun()' aufgerufen wird, wenn das Programm ausgeführt wird, ist 'fun()' der 'Derived' Klasse .. BTW ich spielte mit C++ Konzepten herum, so dass ich auf dieses Problem stieß ... nichts Praktisches .. – Haris

Antwort

2

Zu allererst Ihr Derived::fun() ist auch virtual, denn wenn eine Funktion in einer abgeleiteten Klasse die gleiche Erklärung wie eine virtuelle Funktion in der Basisklasse hat, automatisch die Funktion in abgeleiteten Klasse virtual bekommt, auch wenn diese nicht explizit waren angegeben.

Zweitens ist es völlig in Ordnung, auf private virtuelle Funktionen über öffentliche Zwischenfunktionen aus der Basisklasse zuzugreifen, siehe z. B. this answer und seine Links, insbesondere Virtuality by Herb Sutter. Ein Codebeispiel sein könnte wie

#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; 
} 

Also, was in Ihrem Fall geschieht, denke ich, ist eine ähnliche Situation: der main darf ptr->fun() zugreifen, aber aufgrund Virtua diese fun() geschieht Derived::fun() zu sein.

UPD: auf einen Kommentar erweitern

Aber nicht dieser Ton ein wenig alarmierend ..Ich meine, alle Funktionen , die von der Basisklasse ableiten, werden ihre private Mitglieder zugänglich den Freund Funktionen der Basisklasse haben

Nein, nicht alle Funktionen von Derived werden den Freunden zugänglich sein, Base, aber nur diejenigen, die über Base Zeiger erreichbar sind. Zum Beispiel:

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; 
} 

anzumerken, dass virtual Funktion absichtlich erweiterbare und jede Überschreibung von virtual Funktion in Derived bedeutet, dass die Funktion kann über Base genannt werden:

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

nur Derived::fun() können vom Haupt zugegriffen werden Zeiger; Dies ist der Hauptzweck von virtual Funktionen. Wenn Derived seine vorrangige Funktion private macht, sollte es immer noch bewusst sein, dass die Funktion über Base Zeiger zugegriffen werden kann, denn das ist die Grundidee hinter den virtual Funktionen.

+0

ook. Aber klingt das ein wenig beunruhigend. Ich meine, alle Funktionen, die von der Base-Klasse abstammen, werden ihre privaten Mitglieder den Friend-Funktionen der Base-Klasse zugänglich machen. – Haris

+0

@haris, nein! Nur die 'virtuellen' Funktionen, die bereits in' Base' vorhanden waren! Ich werde die Antwort in einer Minute erweitern. – Petr

+1

@haris, erweiterte die Antwort – Petr

0

Dies passiert, weil Sie fun als virtuell deklariert haben. Zur Laufzeit, wenn die vtable durchsucht wird, findet sie den Eintrag für Derived::fun() und springt damit zur Adresse.

Die Freund-Funktionen werden jedoch nicht geerbt, Sie können dies überprüfen.

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; 
} 

Hier Privat Mitglied Derivedm ist zur Haupt nicht zugänglich.

+0

Ich habe Sie nicht verstanden, das Programm greift auf die private Funktion der Derived Klasse von' main() 'zu function .. wie macht 'fun()' Funktion in der Basisklasse virtuelle Effekte, die .. – Haris

+0

@Nishant ich bezweifle vtables arbeiten so .. siehe diese Beschreibung http://imgur.com/6e23Roa – Haris

+0

@DenisZaikin ja, offensichtlich es wird "Base Fun" sein, weil ptr auf das Objekt von abgeleitet zeigt, das ein Unterobjekt der Basis hat. – Nishant

1

Friend Funktionen nehmen niemals an der Vererbung teil.

Was passiert hier?
Wenn virtuelle Methode in Base Klasse definiert ist, ist eine virtuelle Tabelle enthält createdwhich Adresse fun Methode der Base Klasse. Und da, Derived Klasse erbt, enthält die VTABLE auch die Adresse Derived Klasse fun Methode. Nun, da main die Friend-Funktion der Klasse Base ist, ermöglicht der Compiler den Zugriff seiner Mitglieder auf die Methode main unabhängig von ihrem Zugriffsspezifizierer. Daher erhält main die Adresse Derived::fun und Derived Klasse fun wird zur Laufzeit aufgerufen.