23 Виртуальные базовые
классы. "Друзья" классов (friend).
При множественном наследовании базовый класс не может быть задан в производном классе более одного раза
class В { ... };
class D : В, В {…}: // недопустимо
Однако базовый класс может быть передан производному классу более одного раза косвенно
class Х :
publ ic В {...}
class Y : public В { ... }
class Z : public X, public Y {…} // ДОПУСТИМО
В данном случае каждый объект класса Z будет иметь два подобъекта класса В. Если это вызывает проблемы, к спецификатору базового класса может быть добавлено ключевое слово virtual, например:
class X :
virtual public B {…}
class Y :
virtual public B {…}
class Z :
public X, public Y {…}
Теперь B является виртуальным базовым классом, а класс Z имеет только один подобъект класса В.
"Друзья"
классов (friend)
Friend F класса X — это функция или класс, которые, не являясь методом X. имеют полные права доступа к private и protected компонентам X. Во всех прочих отношениях F — это с точки прения области действия, объявлений и определений обычная функция.
Поскольку F не является элементом X, она не лежит в области действиях и поэтому не может вызываться операциями выбора x.F и xptr->F (где х — объект X, a xptr — указатель объекта X).
Если в объявлении или определении функции в пределах класса Х используется спецификатор friend, то такая функция становится "другом" класса X.
Дружественная функция, определенная в пределах класса. подчиняется тем же правилам встраивания, что и методы (см. "Встраиваемые функции").
Функции-"друзья" не зависят от их позиции в классе и спецификаторов доступа, например:
class Х {
int i; // private относительно Х
friend
void friend_func(X*,
int);
/* friend_func не
является private */
public:
void member_func (int);
};
/* определения; для обеих функций отметим доступ к private int i */
void friend_func(X* xptr, int a) { xptr->i=a; }
void X::member_func(int a) { i=a; }
X xobj;
/* отметим различие в вызовах функций */ (
friend_func(&xobj,6);
xobj.member_func(6);
Можно сделать все функции класса Y друзьями класса Х в одном объявлении
class Y; // неполное объявление
class Х {
friend Y;
int i;
void member_funcX();
};
class Y; { // полное объявление
void friend_X1(X&);
void friend_ X2(X*);
…
};
Функции, объявленные в Y, являются друзьями X, хотя они и не имеют спецификаторов friend. Они имеют доступ к private элементам X, таким, как i и member_funcX.
Отдельные методы Х также могут быть друзьями класса Y
class Х {
…
void member_funcX();
}
class Y {
int i;
friend
void X::member_funcX();
…
};
"Дружба" классов не транзитивна: если Х друг Y, a Y друг Z, это не означает, что Х друг Z. Однако "дружба" наследуется.