Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
МВ_Прог_1курс_2n1часть.doc
Скачиваний:
11
Добавлен:
13.04.2015
Размер:
735.74 Кб
Скачать

6 Наслідування, поліморфізм, інкапсуляция

6.1 Мета роботи

6.2 Вказівки щодо організації самостійної роботи студентів

    1. Наследование

Производный класс (наследник) может получать атрибуты и поведение уже существующего базового класса. Наследование позволяет “вынести за скобки” то общее, что присуще нескольким классам — общие свойства придаются базовому классу, а отличия — его наследникам.

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

class date {

int day, month, year;

public:

date(int,int,int);

date(char*);

};

class birthday: public date {

public:

string name;

};

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

Деструктор класса-наследника всегда вызывает деструктор базового класса.

    1. Уровни доступа

Любой элемент класса имеет один из трех уровней доступа:

  • private(закрытый) – доступен только из функций-членов данного класса и дружественных функций;

  • protected(защищенный) – доступен какprivate, а также из функций-членов производных классов;

  • public(открытый) – доступен всюду, где виден класс.

В объявлении класса обычно сначала перечисляются все открытые элементы, потом защищенные, потом закрытые.

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

class Derived: сп_доступа Base1 [, сп_доступа Base2,...] {...};

Замечание. Базовых классов больше одного, если наследование множественное.

Спецификаторы определяют уровень доступа к элементам базового класса внутри производного. Уровень доступа к элементу определяется как меньший из двух - того, что элемент имеет внутри базового класса и того, что указан в производном классе (private<protected<public).

Явное указание спецификатора доступа при наследовании не обязательно. По умолчанию принимается private для базовых классов и public для базовых структур и объединений.

Если базовый класс наследуется как private, его публичные элементы будут иметь уровень private в производном классе. Однако можно выборочно вернуть статус публичных некоторым элементам базового класса, переобъявив их в секции public производного класса.

Пример. Возврат утраченного статуса.

class Base {

public:

void f1();

};

class Derived: private Base {

public:

Base::f1; // делает f1() снова публичным

};

Если элемент описан в базовом классе как private, его никак нельзя сделатьpublicв производном классе.

    1. Виртуальные функции

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

Пример. Класс с виртуальными функциями.

Определим базовый класс date

class date {

protected:

int day, month, year;

public:

date(int,int,int);

void set_year(int y);

void print();

};

date::date(int d, int m, int y)

{

day = d; month = m; year = y;

}

void date::set_year(int y)

{

year = y;

print();

}

void date::print()

{

printf("%d-%d-%d\n", day, month, year);

}

и производный от него класс birthday:

class birthday: public date {

public:

char name[80];

birthday(int d, int m, int y, char* n);

void print();

};

birthday::birthday(int d, int m, int y, char* n) : date(d, m, y)

{

strcpy(name, n);

}

void birthday::print()

{

printf("%d-%d-%d, dear %s\n", day, month, year, name);

}

Следующий код

date* d = new date(19, 10, 1951);

birthday* b = new birthday(19, 10, 1951, "Bond");

d->set_year(2001);

b->set_year(2001);

напечатает: "19-10-1951" два раза.

Если же сделать метод date::print() виртуальным,

virtual void print(int y);

то тот же код напечатает:

"19-10-1951"

"19-10-1951, dearBond".

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

Для виртуальных функций действуют следующие правила:

  1. виртуальную функцию нельзя объявлять как static; .

  2. спецификатор virtual писать не обязательно при переопределении функции в производном классе, переопределенная функция все равно будет виртуальной.

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

virtual void print() = 0;

Класс, содержащий чисто виртуальные функции, является абстрактным, объекты такого класса не могут быть созданы. Единственным назначением абстрактных классов является “вынесение за скобки” общих свойств их потомков и обеспечение полиморфизма.