friend class Pal; //
};
class Pal {
public:
int f(Base b) { return b.prot_mem; } //
int f2(Sneaky s) { return s.j; } //
//
//
//
int f3(Sneaky s) { return s.prot_mem; } //
};
Факт допустимости функции f3() может показаться удивительным, но он непосредственно следует из правила, что все классы контролируют доступ к собственным членам. Класс Pal — друг класса Base, поэтому класс Pal может обращаться к членам объектов класса Base. Это относится и к встроенным в объект класса Base объектам классов, производных от него.
Когда класс объявляет другой класс дружественным, это относится только к данному классу, ни его базовые, ни производные классы никаких специальных прав доступа не имеют:
//
class D2 : public Pal {
public:
int mem(Base b)
{ return b.prot_mem; } //
};
Иногда необходимо изменить уровень доступа к имени, унаследованному производным классом. Для этого можно использовать объявление using (см. раздел 3.1):
class Base {
public:
std::size_t size() const { return n; }
protected:
std::size_t n;
};
class Derived : private Base { //
public:
//
using Base::size;
protected:
using Base::n;
};
Поскольку класс Derived использует закрытое наследование, унаследованные члены size() и n по умолчанию будут закрытыми членами класса Derived. Объявления using корректируют доступность этих членов. Пользователи класса Derived могут обращаться к функции-члену size(), а классы, впоследствии произошедшие от класса Derived, смогут обратиться к переменной n.
Объявление using в классе может использовать имя любого доступного (не закрытого) члена прямого или косвенного базового класса. Доступность имени, указанного в объявлении using, зависит от спецификатора доступа, предшествующего объявлению using. Таким образом, если объявление using расположено в разделе private класса, то имя будет доступно только для членов и друзей. Если объявление находится в разделе public, имя доступно для всех пользователей класса. Если объявление находится в разделе protected, имя доступно только для членов, друзей и производных классов.
using только для тех имен, доступ к которым разрешен.
В разделе 7.2 упоминалось о том, что у классов, определенных с использованием ключевых слов struct, и class разные спецификаторы доступа по умолчанию. Точно так же заданный по умолчанию спецификатор наследования зависит от ключевого слова, используемого при определении производного класса. По умолчанию у производного класса, определенного с ключевым словом class, будет закрытое наследование (private inheritance), а с ключевым словом struct — открытое (public inheritance):
class Base { /* ... */ };
struct D1 : Base { /* ... */ }; //
class D2 : Base { /* ... */ }; //
Весьма распространенно заблуждение, что между классами и структурами есть иные, более глубокие различия. Единственное различие — заданные по умолчанию спецификаторы доступа для членов и наследования. Никаких других различий нет.
private, не следует полагаться на поведение по умолчанию. Это ясно дает понять, что закрытое наследование применено преднамеренно, а не по оплошности.