Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции C++.doc
Скачиваний:
7
Добавлен:
01.05.2025
Размер:
1.44 Mб
Скачать

5.1.3 Дополнительная спецификация доступа при наследовании

При наследовании базового класса с ключевым словом private все его элементы, включая общедо­ступные члены, становятся частными элементами производного класса. Однако в определенных случаях может потребоваться, чтобы определенные общедоступные элементы базового класса со­хранили свой статус общедоступных в производном классе. Для этого используется объявление доступа. Оно имеет следующую общую форму:

имя_базового_класса::элемент;

Объявление доступа помещается над подходящим заголовком при объявлении производного класса. Ниже представлен пример, иллюстрирующий использование объявления доступа:

#include <iostream.h>

class B

{

public:

int i, j;

};

class D: private B

{

public:

// объявление доступа

B::i; // i из класса B теперь опять публичный

int k;

};

int main()

{

D d;

d.i = 10; // допустимо, поскольку i сделан в D публичным

d.k = 20;

// d.j = 30; // недопустимо, поскольку j в D является частным

cout << d.i * d.k;

return 0;

}

В этом примере класс D наследуется от класса B с ключевым словом private. Это означает, что члены i и j становятся частными членами класса D. Однако в классе D объявление доступа указывает, что член i снова становится общедоступным.

Также можно использовать объявление доступа для того, чтобы предоставить защищенным членам базового класса статус защищенных в производном классе. Однако следует иметь в виду, что нельзя расширить доступ члена. Например, частный элемент базового класса не может стать публичным элементом производного класса.

5.2 Конструкторы и деструкторы производных классов

При использовании производных классов важно представлять себе, каким образом и когда ис­полняются конструкторы и деструкторы базового и производного классов. Начнем рассмотрение с конструкторов.

Как базовый класс, так и производный класс могут иметь конструкторы. (В многоуровневой иерархии классов каждый из классов может иметь конструкторы, но мы начнем с наиболее простого случая.) Когда базовый класс имеет конструктор, этот конструктор исполняется перед конструктором производного класса. Например, рассмотрим следующую короткую программу:

#include <iostream.h>

class Base

{

public:

Base() { cout << "\nBase created\n"; )

};

class D1() : public Base

{

public:

D1() { cout << "D1 created\n"; }

};

int main()

{

D1 d1;

// ничего не делается, но выполняются конструкторы

return 0;

}

Эта программа создает объект класса D1. Она выводит на экран следующий текст:

Base created

D1 created

Здесь d1 является объектом класса D1, производным класса Base. Таким образом, при созда­нии объекта d1 сначала вызывается конструктор Base(), а затем вызывается конструктор D1().

Конструкторы вызываются в том же самом порядке, в каком классы следуют один за другим в иерархии классов. Поскольку базовый класс ничего не знает про свои производные классы, то его инициализация может быть отделена от инициализации производных классов и производит­ся до их создания, так что конструктор базового класса вызывается перед вызовом конструктора производного класса.

В противоположность этому деструктор производного класса вызывается перед деструктором базового класса, поскольку уничтожение объектов должно выполняться в порядке, обратном порядку их создания. Следующая программа иллюстрирует порядок, в котором выполняются конструкторы и деструкторы:

#include <iostream.h>

class Base

{

public:

Base() { cout << "\nBase created\n"; }

~Base() { cout << "Base destroyed\n\n"; }

};

class D1() : public Base

{

public:

D1() { cout << "D1 created\n; }

~D1() { cout << "D1 destroyed\n"; }

};

int main()

{

D1 d1;

return 0;

}

Эта программа выдаст следующий текст на экран:

Base created

D1 created

D1 destroyed

Base destroyed

Производный класс может служить базовым классом для создания следующего производного класса. Когда такое происходит, конструкторы исполняются в порядке наследования, а деструк­торы — в обратном порядке. В качестве примера рассмотрим следующую программу, использую­щую класс D2, производный от класса D1:

#include <iostream.h>

class Base

{

public:

Base() { cout << "\nBase created\n"; }

~Base() { cout << "Base destroyed\n"; }

};

class D1() : public Base

{

public:

D1() { cout << "D1 created\n"; }

~D1() { cout << "D1 destroyed\n"; }

};

class D2: public D1

{

public:

D2() { cout << "D2 created\n"; }

~D2() { cout << "D2 destroyed\n"; }

};

int main()

{

D1 d1;

D2 d2;

return 0;

}

Эта программа выдаст следующий результат:

Base created

D1 created

Base created

D1 created

D2 created

D2 destroyed

D1 destroyed

Base destroyed

D1 destroyed

Base destroyed

ПАМЯТКА: Следует запомнить, что конструкторы вызываются в том порядке, в котором классы выводились один из другого. Порядок вызова деструкторов обратный.