friend void clobber(Sneaky&); //
friend void clobber(Base&); //
int j; //
};
//
void clobber(Sneaky &s) { s.j = s.prot_mem = 0; }
//
void clobber(Base &b) { b.prot_mem = 0; }
Если производные классы (и друзья) смогут обращаться к защищенным членам в объекте базового класса, то вторая версия функции clobber
(получающая тип Base&
) будет корректна. Хоть эта функция и не дружественна классу Base
, она все же сможет изменить объект типа Base
; для обхода защиты спецификатором protected
любого класса достаточно определить новый класс по линии Sneaky
.
Для предотвращения такого способа применения члены и друзья производного класса могут обращаться к защищенным членам
Доступ к члену наследуемого класса контролируется комбинацией спецификатора доступа этого члена в базовом классе и спецификатором доступа в списке наследования производного класса. Для примера рассмотрим следующую иерархию:
class Base {
public:
void pub_mem(); //
protected:
int prot_mem; //
private:
char priv_mem; //
};
struct Pub_Derv : public Base {
//
int f() { return prot_mem; }
//
char g() { return priv_mem; }
};
struct Priv_Derv : private Base {
//
int f1() const { return prot_mem; }
};
Спецификатор доступа наследования никак не влияет на возможность членов (и друзей) производного класса обратиться к членам его собственного прямого базового класса. Доступ к членам базового класса контролируется спецификаторами доступа в самом базовом классе. Структуры Pub_Derv
и Priv_Derv
могут обращаться к защищенному члену prot_mem
, но ни одна из них не может обратиться к закрытому члену priv_mem
.
Задача спецификатора доступа наследования — контролировать доступ пользователей производного класса, включая другие классы, производные от него, к членам, унаследованным от класса Base
:
Pub_Derv d1; //
Priv_Derv d2; //
d1.pub_mem(); //
d2.pub_mem(); //
Структуры Pub_Derv
и Priv_Derv
унаследовали функцию pub_mem()
. При открытом наследовании члены сохраняют свой спецификатор доступа. Таким образом, объект d1
может вызвать функцию pub_mem()
. В структуре Priv_Derv
члены класса Base
являются закрытыми; пользователи этого класса не смогут вызвать функцию pub_mem()
.
Спецификатор доступа наследования, используемый производным классом, также контролирует доступ из классов, унаследованных от этого производного класса:
struct Derived_from_Public : public Pub_Derv {
//
int use_base() { return prot_mem; }
};
struct Derived_from_Private : public Priv_Derv {
//
int use_base() { return prot_mem; }
};