关于c ++友谊和VC12和VC14继承的不同行为

rnd*_*gen 5 c++ inheritance friend visual-studio

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

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

class Third
{
     void foo() 
     {
        Derive d;
        d.func1();
     }
};
Run Code Online (Sandbox Code Playgroud)

我可以编译VC14(Visual Studio 2015)中的代码但是没有错误,但从VC12中获取错误(Visual Studio 2013)

cannot access protected member declared in class 'Base'
Run Code Online (Sandbox Code Playgroud)

谁对吗?具有继承权的这种自由的正确性是什么?

来自MSDN https://msdn.microsoft.com/en-us/library/465sdshe.aspxhttp://en.cppreference.com/w/cpp/language/friend看起来这种友谊不是传递性的,不可能是遗传.但是我认为这个代码示例的情况并非如此.

但为什么VC14不会给我一个错误?

如果VC14是正确的,我怎么能"修改"代码,这样VC12也可以呢?在类Derived中再次定义受保护的func1()?

Ric*_*ges 4

修正错别字后,内嵌评论:

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();
     }
};
Run Code Online (Sandbox Code Playgroud)

VC14是正确的。

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();
     }
};
Run Code Online (Sandbox Code Playgroud)

另一种可能的解决方法(使用基于密钥的访问)

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());
     }
};
Run Code Online (Sandbox Code Playgroud)