Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 271
rnd_nr_gen Avatar asked Sep 21 '16 08:09

rnd_nr_gen


1 Answers

after fixing the typos, comments 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 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());
     }
};
like image 147
Richard Hodges Avatar answered Oct 18 '22 06:10

Richard Hodges