Выбрать главу

Объявление доступа помещается в производном классе под соответствующим спецификатором доступа. Обратите внимание на то, что объявления типа в этом случае указывать не требуется.

Чтобы понять, как работает объявление доступа, рассмотрим сначала этот короткий фрагмент кода.

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-статус нужно вернуть лишь нескольким членам. И все же к этому средству лучше прибегать только в крайних случаях.

Чтение С++-графов наследования

Иногда иерархии С++-классов изображаются графически, что облегчает их понимание. Но порой различные способы изображения графов наследования классов вводят новичков в заблуждение. Рассмотрим, например, ситуацию, в которой класс А наследуется классом В, который в свою очередь наследуется классом С. Используя стандартную С++-систему обозначений, эту ситуацию можно отобразить так: