2016-09-21 14 views
5
class Base 
{ 
protected: 
    void func1(); 
}; 

class Derived : public Base 
{ 
friend class Third; 
}; 

class Third 
{ 
    void foo() 
    { 
     Derive d; 
     d.func1(); 
    } 
}; 

mogę skompilować kod w VC14 (Visual Studio 2015) Błąd withour ale się błąd z VC12 (Visual Studio 2013)Different zachowanie o C++ Przyjaźni i dziedziczenia z VC12 i VC14

cannot access protected member declared in class 'Base' 

którzy jest w porządku? Jaka jest poprawność takiego freindship z dziedziczenia?

z MSDN https://msdn.microsoft.com/en-us/library/465sdshe.aspx lub http://en.cppreference.com/w/cpp/language/friend Wygląda na to, że przyjaźń nie jest przechodnia i nie może zostać odziedziczona. Jednak myślę, że tak naprawdę nie jest tak w przypadku tego przykładu kodu.

Ale dlaczego VC14 nie dostarczy mi błędu?

Jeśli VC14 ma rację, w jaki sposób mogę "zmodyfikować" kod tak, aby VC12 również było w porządku? aby zdefiniować chronione func1() ponownie w klasie Derived?

+0

wątpię można skompilować ten kod w dowolnym kompilatorem: to brakuje niektórych średników. – rubenvb

+0

Błąd nie działa na GCC http://ideone.com/Zue7WL. –

+0

Dobre pytanie. Transwersja i dziedziczenie nie mają zastosowania, ponieważ jest to klasa pochodna, która deklaruje Trzecie jako przyjaciela. Kod jest akceptowany przez clang i gcc. – drRobertz

Odpowiedz

4

po ustalające literówki, komentarze inline:

class Base 
{ 
protected: 
    void func1(); // protected access 
}; 

class Derived : public Base 
{ 
    // implicit protected func1, derived from Base 

    // this means 'make all my protected and private names available to Third' 
    friend class Third; 
}; 

class Third 
{ 
    void foo() 
    { 
     Derived d; 
     // func1 is a protected name of Derived, but we are Derived's friend 
     // we can therefore access every member of Derived 
     d.func1(); 
    } 
}; 

VC14 jest poprawna.

Możliwe obejście VC12:

class Base 
{ 
protected: 
    void func1(); 
}; 

class Derived : public Base 
{ 
    protected: 
    using Base::func1; 

    private: 
    friend class Third; 
}; 


class Third 
{ 
    void foo() 
    { 
     Derived d; 
     d.func1(); 
    } 
}; 

Innym możliwym obejście (używając klawisz dostępu opartego)

class Third; 
class Func1Key 
{ 
    private: 
    Func1Key() = default; 
    friend Third; 
}; 

class Base 
{ 
protected: 
    void func1(); 
}; 

class Derived : public Base 
{ 
public: 
    void func1(Func1Key) 
    { 
    Base::func1(); 
    } 
}; 


class Third 
{ 
    void foo() 
    { 
     Derived d; 
     d.func1(Func1Key()); 
    } 
}; 
+0

@songyuanyao Mam na myśli to, że jest to prywatne, o ile inna klasa wyglądająca w –

+0

@juanchopanza została poprawiona. –

+0

@songyuanyao poprawione. Dziękuję Ci. –