2015-07-22 16 views
6

Metoda fun() w klasie pochodnej jest prywatna. Kiedy wywołujemy funkcję ptr->fun() poprzez polimorfizm czasu wykonywania, jest ona wykonywana. Ale to narusza właściwość enkapsulacji klasy pochodnej.Czy funkcja przyjaciela jest tutaj dziedziczona?

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

Czy ktoś może wyjaśnić, co się dzieje?

+0

znajomi mają dostęp do prywatnych członków. Deklarujesz głównego jako przyjaciela, więc masz dostęp do prywatnych członków. (dlaczego zrobiłeś to dla mnie cudem) – user463035818

+0

@ tobi303, znajomy ma dostęp do prywatnego zbioru 'Base', a nie' Derived' i 'fun()' podczas wywoływania programu jest 'fun()' z 'Derived' class .. BTW grałem z koncepcjami C++, więc natknąłem się na to .. nic praktycznego .. – Haris

Odpowiedz

2

Przede wszystkim, Derived::fun() jest również virtual, bo jeśli funkcja w klasie pochodnej ma taką samą deklarację jako funkcję wirtualną w klasie bazowej, funkcja w klasie pochodnej automatycznie pobiera virtual, nawet jeśli nie było wyraźnie określony.

Po drugie, dostęp do prywatnych funkcji wirtualnych za pośrednictwem publicznych pośrednich funkcji klasy podstawowej jest całkowicie OK, patrz na przykład this answer i jego linki, w szczególności Virtuality by Herb Sutter. Próbkę kodu może być jak

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

Więc, co dzieje się w twoim przypadku, myślę, że jest podobna sytuację: main ma dostępu do ptr->fun(), ale ze względu na wirtualności tego fun() bywa Derived::fun().

UPD: rozszerzenie na komentarzu

ale nie brzmi to trochę niepokojącą ..To znaczy, wszystkie funkcje że wywodzą się z klasy bazowej, będzie miał ich prywatnymi członków dostęp do funkcji przyjaciel klasie Base

Nie, nie wszystkie funkcje Derived będą dostępne dla przyjaciół Base, ale tylko te, które mogą być dostępne za pośrednictwem wskaźnika Base. Na przykład:

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

Derived::fun() można uzyskać tylko od głównej:

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

Zauważ, że virtual funkcja są celowo rozszerzalny, a wszelkie ominięcie virtual funkcji w Derived oznacza, że ​​funkcja ta może być wywołana poprzez Base wskaźnik; to jest główny cel funkcji virtual. Jeśli Derived tworzy funkcję nadrzędną private, nadal powinno być świadome, że funkcja jest dostępna za pośrednictwem wskaźnika Base, ponieważ jest to główny pomysł funkcji virtual.

+0

ook. Ale czy to nie brzmi trochę niepokojąco ... Mam na myśli, że wszystkie funkcje wywodzące się z klasy "Base", będą miały swoich prywatnych członków dostępnych dla funkcji przyjacielskich klasy "Podstawowej". – Haris

+0

@haris, nie! Tylko funkcje 'wirtualne', które już tam były w' Base'! Rozwiążę odpowiedź za minutę. – Petr

+1

@haris, rozwinął odpowiedź – Petr

0

To się dzieje, ponieważ zadeklarowałeś fun jako wirtualny. W czasie wykonywania, gdy jest poszukiwany vtable, znajduje wpis dla Derived::fun(), a tym samym przeskakuje na adres.

Jednak funkcje znajomego nie są dziedziczone, możesz to sprawdzić za pomocą tego.

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

Tutaj prywatny członkiem Derivedm nie jest przystosowany do main.

+0

Nie dostałem cię, program uzyskuje dostęp do prywatnej funkcji klasy Derived z' main() ' funkcja ... jak robi funkcję 'fun()' w efektach wirtualnych klasy podstawowej, które .. – Haris

+0

@Nishant i wątpię, vtables działają w ten sposób .. zobacz ten opis http://imgur.com/6e23Roa – Haris

+0

@DenisZaikin tak, oczywiście będzie to "Podstawowa zabawa", ponieważ ptr wskazuje na obiekt wyprowadzony, który ma podobiekt podstawy. – Nishant

1

Friend funkcje nigdy nie biorą udziału w dziedziczeniu.

Co się tutaj dzieje?
Po zdefiniowaniu wirtualnej metody w klasie Base tworzona jest tabela wirtualna, która zawiera adres metody fun klasy fun klasy fun. A ponieważ dziedziczy je klasa Derived, VTABLE zawiera również adres metody Derived klasy fun. Teraz, od main jest funkcją przyjaciela klasy Base, kompilator umożliwia dostęp do jej członków do metody main niezależnie od ich specyfikatora dostępu. W związku z tym main dostaje adres Derived::fun i klasa fun zostaje wywołana w czasie wykonywania.

Powiązane problemy