elgcom elgcom - 2 months ago 6
C++ Question

Different behavior about c++ Friendship and inheritance from VC12 and VC14

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

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

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


I can compile the code in VC14 (Visual Studio 2015) withour error
but get error from VC12 (Visual Studio 2013)

cannot access protected member declared in class 'Base'


who is right?
what is the correctness of such freindship with inheritence?

from MSDN https://msdn.microsoft.com/en-us/library/465sdshe.aspx or http://en.cppreference.com/w/cpp/language/friend It looks like that friendship is not transitive and cannot be inherited. However I think it is not really the case of this code example.

But why VC14 won't get me an error?

If VC14 is right, how can I "modify" the code so that VC12 is also ok with that?
to define protected func1() again in the class Derived?

Answer

after fixing the typos, comments inline:

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

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 see everything Derived can see
        d.func1();
     }
};

VC14 is correct.

Possible workaround for 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();
     }
};

Another possible workaround (using key-based access)

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