класс 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
методы класса напрямую, но вы можете получить к ним доступ через указатель. 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
}
};
доступ к членам данных и статическим данным тоже прост