Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТООП конспект весь.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
21.89 Mб
Скачать

Int main()

Derived d(5, 10);

/*после b класса Base является закрытым, поэтому он недоступен в методах производного класса Derived */

Если поле в базовом классе объявлено как protected, то для чужих классов и внешних функций оно будет недоступно, а для классов наследников – доступно.

Поля, доставшиеся классу наследнику от родительского класса должны инициализироваться конструктором этого родительского класса, поэтому при создании объекта производного класса обязательно явно или неявно вызывают конструктор базового класса. Если неявно, то вызывается конструктор без аргументов.

Если у базового класса нет такого конструктора, то вызываемый конструктор должен быть указан явно в списке инициализации конструктора производного класса.

int x=d.getB();

Base *bp;

pb=&d;

/*через указатель на базовый класс pb доступны только имена, объявленные только в этом базовом классе.*/

(x) pb -> getD(); //нельзя

(pb -> getB();)

Методы базового класса нужно переопределить в производном классе.

Виды наследования в С++.

Base

Прямая со стрелкой 2 -b1 : int

+ b2 : int

# b3 : int

Соединительная линия уступом 12 Derived

-d : int

public, private, protected

DerDer



Прямая со стрелкой 13 +b3

Int main()

Закрытое поле недоступно ни наследникам, ни внешним функциям.

Открытое поле доступно и наследникам и внешним функциям.

Защищенное поле доступно наследникам, но недоступно внешним функциям и другим классам.

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

Вид наследования влияет на доступ из внешних функций (чужих классов) на те поля и методы, которые достались производному классу от базового класса.

Derived x(1,2);

Вид наследования может поменять разрешения, заданные в базовом классе.

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

b1 из main посмотреть и изменить нельзя.

b2 из main можно посмотреть и изменить.

b3 из main посмотреть и изменить нельзя.

x.b1 x.b2 x.b3

x x x

b3x в классе внутри.

Если наследование закрытое, тогда все поля и методы базового класса во внешней функции становятся закрытыми.

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

в классе внутри +b3

x.b1 x.b2 x.b3

x x x

Пример:

Собственный класс стек на основе чужого класса List, созданный с помощью наследования.

List.h

List.h

+add (int index, int elem)

+del (int index)

+get (int index) : int

+isEmpty () : int

+size () : int

Stack

+push (int elem)

+pop () : int

+top () : int

Stack.h

#include “List.h”

class Stack : private List /*class stack : List {*/

{

public:

void push (int);

int pop ();

int top (); //(*)

}

Stack.cpp

#include “Stack.h”

void stack:: push (int elem)

{

add(elem);

}

int stack:: pop ()

{

int tmp = get(0);

del(0);

return tmp;

}

int stack:: top ()

{

return get(0);

}

Данная реализация содержит проблему: стек ведет себя как список, все открытые методы класса List можно вызвать для объектов класса stack.

Чтобы решить проблему, изменяем вид наследования.

Осталась еще одна проблема: метод isEmpty стал недоступен для класса stack.

Решить проблему можно:

  1. переопределив isEmpty в классе stack, поместив его в секцию public (подход в стиле агрегирования)

  2. можно использовать конструкцию восстановления доступа: в описании класса stack нужно добавить (*):

using List:: isEmpty;

Принципиально важно, в какой секции размещается using. Чтобы сделать isEmpty открытым нужно размещать using в секции public (можно в секции public написать просто List:: isEmpty).

Можно использовать using в противоположных целях, чтобы закрыть открытые имена из базового класса. Тогда using нужно размещать в закрытой (private) секции.

Можно использовать using многократно.

Если метод в базовом классе перегружен, то конструкция using влияет на все эти методы.

Для такой задачи естественным является отношение агрегирования, так как класс stack обладает меньшими возможностями, чем List (сужает, а не расширяет List).

В java и C#:

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

  2. нельзя открытый метод базового класса переопределить в наследнике, как закрытый (наследник не будет похож на родителя).

Наследование в java и C#.

В java используются слова extends.

class Base {}

class Derived extends Base {}

В языке C#

class Base {}

class Derived : Base {}

Переопределение методов базового класса в классе наследнике.

Если имя метода в произвольном классе совпадает с именем метода в базовом классе, возможно:

  1. перегрузка методов

  2. сокрытие методов

  3. переопределение методов

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

Пример:

class Base

{

public:

void fun1() {}

void fun2() {}

};

class Derived : public Base

{

public:

void fun1(int a) {} //перегрузка

void fun2() {} // сокрытие, если С++// в java вызывает Base : fun2 (-> super fun2)

};

C++: