【问题标题】:friend class with inheritance具有继承的朋友类
【发布时间】:2012-11-30 09:57:46
【问题描述】:

如果我有两个继承类如下:

class A
{
    ...
}

class B : public A
{
    ...
}

第三类定义为朋友类A:

class C
{
    friend class A;
}

我能否从class B(也是A 类型的对象)访问class C 的所有成员,就像我首先定义了class B 朋友类一样?

【问题讨论】:

  • 当你尝试它时会发生什么?您尝试的时间比我们回答的时间短。
  • 对不起,我应该补充一点,我已经尝试过但它不起作用,我认为这很令人惊讶......
  • 不起作用,这意味着您无法从 B 类访问 C 类的所有成员?
  • 喜欢吹毛求疵就叫它,但B不是A类的对象,它继承自A。
  • @RobertHarvey 是的,如果我尝试从 B 类的函数访问 C 类的受保护/私有成员,我会收到“不可见”错误。我想这回答了我的问题,但我正在寻找一个理由......

标签: c++ inheritance friend access-control


【解决方案1】:

friendship 既不继承也不传递。这是两个类之间严格的一对一关系。

class A {
  friend class B;  
  int Aries;
};

class B {
  friend class C;  
  int Taurus;
};

class C {
  int Leo;
  void Capricorn() {
    A a;
    a.Aries = 0;  // this wont work, C is not a friend of A.
                // friendship is not transitive
  }
};

class D : public C {
  void Gemini() {
    B b;
    b.Taurus = 0;  // this wont work, D is not a friend of B.
                   // friendship is not inherited
  }
};    

class E : public B {
  void Scorpio() {
    C c;
    c.Leo = 0; // this wont work either, friendship is not inherited
  }
};

参考:“C++ 编程语言”Bjarne Stroustrup

更多解释(我的):如果friendship 不是一对一的,那将是封装的结束。请注意,B 类只能访问Aprivate 成员,前提是A 的类声明将B 声明为friendB 不能在 A 上强制执行 friendship。

现在,如果友谊可以被继承,那么某人只需要继承B 即可访问A 的私有成员,而A 没有任何发言权来阻止它。此外,允许friendship 传递会导致其他问题,因为现在B 可能有一个friend C,而后者又可能有一个friend D,一直到@987654342 @。所有BCD、...、Z 现在都可以访问Aprivate 成员,这将是一场灾难。

【讨论】:

  • 谢谢。从这个答案中学到了很多东西。
  • @Harry 添加了更多解释。 :)
【解决方案2】:

由于某种原因,每个人都忘记了您可以访问派生自友谊给予者的类的虚拟私有函数。

#include <iostream>

class Friend;
class Parent
{
    friend class Friend;
private:
    virtual void nameYourself() { std::cout << "Parent" << std::endl; }
};

class Child : public Parent
{
private:
    virtual void nameYourself() { std::cout << "Child" << std::endl; }
};

class Friend
{
public:
    void foo(Parent *p) { p->nameYourself(); }
};

int main()
{
    Parent p;
    Child c;
    Friend f;
    f.foo(&p);
    f.foo(&c);
    return 0;
}

上面代码运行的输出是:

Parent
Child

它起作用的原因很棘手,并且与该指针的传递方式有关(查找 vtables)。如果您从函数声明中删除“virtual”关键字,您将失去此能力。

【讨论】:

  • 我相信 OP 询问了如何从 Child 访问 Friend 的私​​人成员,而不是如何从 Friend 访问 Child 的私人成员。
【解决方案3】:

引用标准,C++11 11.3/10:

友谊既不是遗传的也不是传递的。

意味着朋友的派生类和朋友的朋友都不能获得友谊的好处。

【讨论】:

    【解决方案4】:

    在上面我发现有用的蒙面人的答案/代码中添加了一个示例:

    class B {
      friend class F;
      friend class E;
      int Taurus;
    };
    
    class E : public B {
      int Egg;
    };
    
    class F {
        void Foo () {
           B b;
           b.Taurus = 4;  //Works F is friend of B (of course)
           E e;
           e.Taurus = 6; // Works E is derived from B and F is friend of B 
                      // Taurus is private member of B.
           e.Egg = 5; // Does not work, F is friend of Base Class B but not
                   // E, so can't access members of the derived class
        }
    };
    

    【讨论】:

      【解决方案5】:

      我认为这取决于。您将可以从 B 的 A 部分(切片部分)访问。如果你定义了 B 自己的函数,我想你不会。

      【讨论】:

        【解决方案6】:

        我不明白您要做什么,但 B 是 A 的超类。不是对象。 B和C之间没有任何继承关系

        【讨论】:

        • 没有。这里 A 是 B 的超类。我意识到 B 和 C 之间没有任何继承关系,只有友谊。
        【解决方案7】:
        • 不 - 它不是继承的(见下文);如果 B 是 A 的子类且 C 是 A 的朋友,则 B 无权访问 C 的私有成员,包括继承的成员。
        • 同样,如果 A 是 C 的朋友,或者如果 A 和 C 都是彼此的朋友,这不会让 B 访问 C 的私有成员,包括继承的成员。
        • 此 URL 声明朋友类的子类不继承朋友关联:

          C++ friend inheritance?

        • 这适用于“关联(主类自己的和与主类交友的其他类)”——这里的问题是后一种情况。

        【讨论】:

          【解决方案8】:

          不,您不能直接调用C 类方法,但可以通过指针访问它们。 A类应该修改:

          class C
          {
            void method()
            {
            }
            friend class A;
          };
          
          class A
          {
          protected:
            constexpr static void (C::*f)() = &C::method;
          };
          
          class B : public A
          {
            B()
            {
              //C().method(); ← This wont work
              (C().*f)(); // ← This works fine
            }
          };
          

          访问数据成员和静态数据也很简单

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-23
            • 2014-01-09
            • 1970-01-01
            • 1970-01-01
            • 2020-02-24
            相关资源
            最近更新 更多