класс friend с наследованием

если у меня есть два класса с наследованием:

class A
{
    ...
}

class B : public A
{
    ...
}

и третий класс с определенным как класс A друга:

class C
{
    friend class A;
}

смогу ли я получить доступ из class B (который также является объектом типа A) все члены class C как будто я определил class B класс друзей в первую очередь?

8 ответов


friendкорабль не наследуется и не является транзитивным. Это строго одно отношение между двумя классами.

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

больше объяснения (мое): если friendкорабль не был один-один, это был бы конец инкапсуляции. Обратите внимание, что B класс может получить доступ к private члены A только если объявление класса A объявляет B as friend. B не может применять friendкорабль on A.

теперь, если дружба может быть унаследована, то кто-то просто должен унаследовать B для доступа к частным членам A, без A имея какое-либо слово в предотвращении этого. Кроме того, позволяя friendкорабль должен быть транзитивным приведет к другим проблемам, так как сейчас B может быть friend C, который в свою очередь может иметь friend D до Z. Все B, C, D, ..., Z теперь можно получить доступ A ' s private члены, что было бы катастрофой.


по какой-то причине все забыли, что вы можете получить доступ к виртуальным частным функциям класса, который происходит от дающего дружбу.

#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" из объявления функции, вы потеряете эту способность.


чтобы процитировать стандарт, C++11 11.3 / 10:

дружба не является ни наследственной, ни транзитивной.

означает, что ни производные классы друзей, ни друзья друзей не получают преимуществ дружбы.


еще один пример добавления к ответу/коду человека в маске выше, который я нашел полезным:

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

Я думаю, что это зависит. У вас будет доступ из части A B (нарезанная часть). Если вы определили собственную функцию B, Я думаю, вы этого не сделаете.


Я не понял, что вы пытаетесь сделать, но B является суперклассом A. не является объектом. Между B и C нет никаких отношений наследования


  • нет-он не наследуется (см. ниже); если B является подклассом A, А C является другом A, B не имеет доступа к частным членам C, включая унаследованные члены.
  • аналогично, если A является другом C, или если оба A и C являются взаимно друзьями друг друга, это не дает B доступ к частным членам C, включая унаследованные члены.
  • этот URL-адрес указывает, что подклассы классов friend не наследуют друг ассоциации:

    наследование друга C++?

  • это относится как к" ассоциациям (как к собственному классу основного класса, так и к другим классам, связанным с основным классом) " - вопрос в последнем случае здесь.


нет, вы не можете позвонить 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
  }
};

доступ к членам данных и статическим данным тоже прост