Объявление доступа помещается в производном классе под соответствующим спецификатором доступа. Обратите внимание на то, что объявления типа в этом случае указывать не требуется.
Чтобы понять, как работает объявление доступа, рассмотрим сначала этот короткий фрагмент кода.
class base {
public:
int j; // public-доступ в классе base
};
// Класс base наследуется как private-класс.
class derived: private base {
public:
// Вот использование объявления доступа:
base::j; // Теперь член j снова стал открытым.
// . . .
};
Поскольку класс base наследуется классом derived закрытым способом, его public-переменная j становится private-переменной класса derived. Однако включение этого объявления доступа
base::j;
в классе derived под спецификатором public восстанавливает public-статус члена j.
Объявление доступа можно использовать для восстановления прав доступа public- и protected-членов. Однако для изменения (повышения или понижения) статуса доступа его использовать нельзя. Например, член, объявленный закрытым в базовом классе, нельзя сделать открытым в производном. (Разрешение подобных вещей разрушило бы инкапсуляцию!)
Использование объявления доступа иллюстрируется в следующей программе.
#include <iostream>
using namespace std;
class base {
int i; // private-член в классе base
public:
int j, k;
void seti (int x) { i = x; }
int geti() { return i; }
};
// Класс base наследуется как private-класс.
class derived: private base {
public:
/* Следующие три инструкции переопределяют private-наследование класса base и восстанавливают public-статус доступа для членов j, seti() и geti(). */
base::j; // Переменная j становится снова public-членом, а переменная k остается закрытым членом.
base::seti; // Функция seti() становится public-членом.
base::geti; // Функция geti() становится public-членом.
// base::i; // Неверно: нельзя повышать уровень доступа.
int а; // public-член
};
int main()
{
derived ob;
//ob.i = 10; // Неверно, поскольку член i закрыт в классе derived.
ob.j = 20; // Допустимо, поскольку член j стал открытым в классе derived.
//ob.k =30; // Неверно, поскольку член k закрыт в классе derived.
ob.a = 40; // Допустимо, поскольку член а открыт в классе derived.
ob.seti(10);
cout << ob.geti() << " " << ob.j << " " << ob.a;
return 0;
}
Обратите внимание на то, как в этой программе используются объявления доступа для восстановления статуса public у членов j, seti() и geti(). В комментариях отмечены и другие ограничения, связанные со статусом доступа.
C++ обеспечивает возможность восстановления уровня доступа для унаследованных членов, чтобы программист мог успешно программировать такие специальные ситуации, когда большая часть наследуемого класса должна стать закрытой, а прежний public-или protected-статус нужно вернуть лишь нескольким членам. И все же к этому средству лучше прибегать только в крайних случаях.
Иногда иерархии С++-классов изображаются графически, что облегчает их понимание. Но порой различные способы изображения графов наследования классов вводят новичков в заблуждение. Рассмотрим, например, ситуацию, в которой класс А наследуется классом В, который в свою очередь наследуется классом С. Используя стандартную С++-систему обозначений, эту ситуацию можно отобразить так: