
- •Наследование классов, виртуальные функции
- •Теоретические сведения
- •Передача параметров в базовый класс
- •Типы наследования (уровни доступа к базовому классу)
- •Public – наследование
- •Использование методов
- •Private – наследование
- •Использование методов
- •Protected – наследование
- •Виртуальные функции и полиморфизм
- •Контрольные вопросы
- •Общие требования выполнения работы
Лабораторная работа № 4 (БДЗ 1)
Наследование классов, виртуальные функции
Цель работы: изучить одну из базовых концепций ООП – наследование классов в С++, заключающуюся в построении цепочек классов, связанных иерархически.
Теоретические сведения
Наследование это механизм для создания нового класса из ранее существующего путем добавления новых методов и свойств, это важное свойство присуще всем объектно-ориентированным языкам.
Наследование резко упрощает задачу, позволяя использовать уже созданные и проверенные объекты для наделения их более конкретными свойствами.
Что дает наследование?
Возможность расширить возможности класса без дублирования кода.
Пример: точка(базовый класс) -> круг(наследует точку) -> конус(наследует круг)
Наследование удобно при модернизации уже существующих программ.
В самом деле, поскольку создается новый класс, никак не затрагивающий уже имеющиеся классы, то для программ, использующих старые классы, ничего не меняется.
Однотипность работы с общей частью - все наследники поддерживают интерфейс базового класса.
Поскольку каждый класс-наследник несет в себе элементы базового класса, то все они будут содержать поля и иметь доступ к методам базового класса.
Например, класс child объявляет себя наследником класса parent:
parent – базовый класс
child – производный класс.
Производный класс унаследует от базового класса все поля данных и почти все методы.
Формат наследования:
сlass имя_базового_класса: доступ имя_производного_класса
{ тело производного класса}
Доступ (тип наследования): public, private, protected
Если доступ при наследовании не указан, то действуют стандартные умолчания:
для типа class - доступ private
для типа struct - доступ public
Пример1: Транспортные средства
//--- БАЗОВЫЙ КЛАСС «Транспорт»
class transport
{ // общие данные для всех наследников
int k_num; // число колес
int p_num; // max число пассажиров
public: // интерфейс базового класса
void set_k (int num)
{ k_num=num;}
void set_p (int num)
{ p_num=num;}
int get_p()
{return p_num;}
int get_k()
{return k_num;}
}; //------------- конец определения класса transport
После того, как дано определение транспортного средства (базового класса), его можно использовать для наследников определения конкретных транспортных средств.
//-----ПРОИЗВОДНЫЙ КЛАСС «Вагон»
class g_avto : public transport
{ int gruz; // грузоподъемность
public :
void set_gruz (int q)
{ gruz=q;}
void show(); //прототип ф-ции
}; //------------- конец определения класса g_avto
Класс g_avto наследует все содержимое класса transport, то есть все поля данных и все функции. Кроме того, добавлено поле gruz, а также функции, необходимые для его поддержки - set_gruz () и get_gruz ().
Производный класс:
не имеет доступа к закрытым элементам базового класса (k_num, p_num)
имеет доступ к открытым элементам (все функции)
//--ПРОИЗВОДНЫЙ КЛАСС «Автомашина»
enum car {maz, gazel, jeep};
class mobile:public transport
{car type;
public:
void set_type (car t )
{ type=t;}
void show();
}; //------------- конец определения класса mobile
// Реализация методов для производных классов.
void g_avto:: show()
{cout<< "\nХарактеристики вагона :\n"\
<<"число пассажиров\t"<<get_p()<<endl\
<< "грузоподъемность: " << gruz;
}
void mobile:: show()
{cout<< "\n Характеристики автомобиля :\n "<< "тип - ";
switch (type)
{
case maz : cout<< "фура\n";break;
case gazel : cout<< "грузовик\n"; break;
case jeep : cout<< "джип\n";
}
cout<< "число колес: "<<get_k()<<endl <<"Максимальное число пассажиров: " <<get_p()<<endl;
}
Вызывающая программа создает несколько объектов производных классов, инициализирует их, а затем выводит на печать.
При использовании функции show(), программа автоматически определяет к какому классу идет обращение, ориентируясь по типу объекта, вызывающего метод.
int _tmain(int argc, _TCHAR* argv[])
{ g_avto w;
mobile q;
// инициализация объектов w, q
w.set_p (39); w.set_gruz(5000);
q.set_p(3); q.set_k(6); q.set_type(maz);
// вывод на экран
cout<<"\n--------------------\n";
.show();
cout<<"\n--------------------\n";
q.show();
system ("pause");
return 0;
}
Результат выполнения программы:
Характеристики вагона :
Число пассажиров : 39
Грузоподъемность : 50000
Характеристики автомобиля :
Тип : фура
Максимальное число пассажиров : 3
Часто базовый класс (БК) создаётся только для того, чтобы задать общую часть данных для некоторой группы классов. В этом случае функции БК являются вспомогательными («техническими»), они обслуживают нужды «наследников» (в нашем случае – обеспечивают доступ к закрытым данным). В этом случае объектов базового класса не создается.
Конструкторы и деструкторы при наследовании.
При наследовании возникает два вопроса :
• когда вызываются конструкторы и деструкторы базового и производного классов?
• Как передаются параметры конструкторов базового класса?
Как базовый, так и производный классы могут иметь по нескольку конструкторов, поэтому очень важно правильно понимать в каком порядке они вызываются при создании объектов производного класса.
#include "stdafx.h"
#include <iostream>
using namespace std; class base
{ int p_b;
public:
base()//--------- base-конструктор
{cout<< "Создание объекта base\n";}
~base()
{cout<<"Уничтожение объекта base\n";}
};//-- конец определения базового класса
class derived : public base
{ int p_d;
public:
derived() //------- derived-конструктор
{cout<< "Создание объекта derived \n";}
~derived()//--------- деструктор
{cout<< "Уничтожение объекта derived\n";}
};//-- конец определения произв. класса
int _tmain(int argc, _TCHAR* argv[])
{derived ob; // создание объекта
system ("pause");
return 0;
}
Результат выполнения программы :
Создание объекта base
Создание объекта derived
Уничтожение объекта derived
Уничтожение объекта base