Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_С++_последная.doc
Скачиваний:
42
Добавлен:
07.05.2019
Размер:
876.54 Кб
Скачать

9.1.2. Поля и методы при наследовании

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

class Point2

{ int x; int у;

public: // ...

};

class Point3: public Point2

{ int z;

public: // ...

};

Добавляемые поля должен инициализировать конструктор наследника. Дополнительные поля производного класса могут совпадать и по имени, и по типу с полями базового класса – в этом случае новое поле скрывает поле базового класса, поэтому для доступа к последнему полю в классе-наследнике необходимо использовать префикс-квалификатор базового класса.

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

Если в классе-наследнике имя метода и его прототип совпадают с именем метода базового класса, то говорят, что метод производного класса скрывает метод базового класса. Чтобы вызвать метод родительского класса, нужно указывать его с квалификатором класса. Пример текста программы наследование методов:

class Base

{ int f; int m;

publiс:

Base():f(),m(){} // конструктор без аргументов

Base (int t, int r = 0) // конструктор инициализации

{ f = t; m = r; }

Base& operator++() // префиксный инкремент

{ f++; return *this; }

Base operator++(int) // постфиксный инкремент

{ F t = *this; f++; return t; }

Base& operator+=(const F& r) // сложение с присваиванием

{ f+=r.f; m+=r.m; return *this; }

};

class Derive: public Base

{ public:

Derive& operator--() // новый метод: префиксный декремент

{ f--: return *this; }

};

9.1.3. Вложенные классы и наследование

Ограничений в наследовании вложенных классов нет: внешний класс может наследовать от вложенного и наоборот; вложенный класс может наследовать от вложенного.

class A {}; // внешний класс

class В {

public:

class С: public A {}: // вложенный класс наследует от внешнего

};

class D: public В:: С {}; // внешний класс наследует от вложенного

class E

{ class F: public B::C {}; // вложенный класс наследует от вложенного

};

Нужно следить только за видимостью базового класса в точке наследования. Например, от вложенного класса Е::F «снаружи» наследовать нельзя, так как класс находится в приватной части класса Е и вне его – невидим. Однако допустимо, чтобы еще один вложенный класс внутри Е наследовал от вложенного класса Е::F:

class E

{ class F: public В: :С {};

class G: public F {};

};

9.1.4. Закрытое наследование

Закрытое наследование – это наследование реализации: класс реализован посредством класса. Оно принципиально отличается от открытого: принцип подстановки не соблюдается. Это означает, что нельзя присвоить (во всяком случае, без явного преобразования типа) объект производного класса базовому. Поэтому закрытое наследование хорошо применять в тех случаях, когда требуется иметь функциональность базового класса, но не нужны ни копирование, ни присваивание.

При закрытом наследовании все элементы класса-наследника становятся приватными и недоступными программе-клиенту.

class Base

{ public:

void methodK);

void method2();

};

class Derive: private Base // наследуемые методы недоступны клиенту

{ };

Программа, использующая класс Derive, не может вызвать ни methodK), ни method2(). В наследнике нужно заново реализовать нужные методы, вызвав в методах на­следника методы родителя.

class Derive: private Base // наследуемые методы недоступны клиенту

{ public:

void methodK) { Base: :methodl(); }

void method2() { Base::method2(): }: }:

Префикс при вызове задавать обязательно, иначе возникает рекурсивное обра­щение к методу-наследнику.

Можно открыть методы базового класса с помощью using-объявления, которое имеет следующий синтаксис:

using <имя базового класса>::<имя в базовом классе>: В наследуемом классе это делается так:

class Derive: private Base // наследуемые методы недоступны клиенту

{ public:

using Base::methodl(); }:

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