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

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

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

Как видите, стрелки на этом рисунке направлены вверх, а не вниз. Многие поначалу считают такое направление стрелок алогичным, но именно этот стиль принят большинством С++-программистов. Согласно стилевой графике C++ стрелка должна указывать на базовый класс. Следовательно, стрелка означает "выведен из", а не "порождает". Рассмотрим другой пример. Можете ли вы описать словами значение следующего изображения?

Из этого графа следует, что класс Е выведен из обоих классов С и D. (Другими словами, класс Е имеет два базовых класса С и D.) При этом класс С выведен из класса А, а класс D — из класса В. Несмотря на то что направление стрелок может вас обескураживать на первых порах, все же лучше познакомиться с этим стилем графических обозначений, поскольку он широко используется в книгах, журналах и документации на компиляторы.

Виртуальные базовые классы

При наследовании нескольких базовых классов в С++-программу может быть внесен элемент неопределенности. Рассмотрим эту некорректную программу.

/* Эта программа содержит ошибку и не скомпилируется.

*/

#include

using namespace std;

class base {

 public:

  int i;

};

// Класс derived1 наследует класс base.

class derived1 : public base { public: int j;};

// Класс derived2 наследует класс base.

class derived2 : public base { public: int k;};

/* Класс derived3 наследует оба класса derived1 и derived2. Это означает, что в классе derived3 существует две копии класса base!

*/

class derived3 : public derived1, public derived2 {

 public:

  int sum;

};

int main()

{

 derived3 ob;

 ob.i = 10; // Это и есть неоднозначность: какой именно член i имеется в виду???

 ob.j = 20;

 ob.k = 30;

 //И здесь тоже неоднозначность с членом i.

 ob.sum = ob.i + ob.j + ob.k;

 // И здесь тоже неоднозначность с членом i.

 cout << ob.i << " ";

 cout << ob. j << " " << ob.k << " ";

 cout << ob.sum;

 return 0;

}

Перейти на страницу:

Все книги серии Изучайте C++ с профессионалами

Похожие книги