- •Лабораторная работа № 5. Большое Домашнее Задание (бдз) Наследование классов, виртуальные функции
- •Теоретические сведения
- •Передача параметров в базовый класс
- •Виртуальные функции и полиморфизм
- •Ограничения на использование виртуальных функций
- •Контрольные вопросы
- •Общие требования выполнения работы
- •Обязательные функции для всех вариантов:
Лабораторная работа № 5. Большое Домашнее Задание (бдз) Наследование классов, виртуальные функции
Цель работы: изучить одну из базовых концепций ООП – наследование классов в С++, заключающуюся в построении цепочек классов, связанных иерархически.
Теоретические сведения
Наследование это механизм для создания нового класса из ранее существующего путем добавления новых методов и свойств, это важное свойство присуще всем объектно-ориентированным языкам.
Наследование резко упрощает задачу, позволяя использовать уже созданные и проверенные объекты для наделения их более конкретными свойствами.
Что дает наследование?
Возможность расширить возможности класса без дублирования кода.
Пример: точка(базовый класс) -> круг(наследует точку) -> конус(наследует круг)
Наследование удобно при модернизации уже существующих программ.
В самом деле, поскольку создается новый класс, никак не затрагивающий уже имеющиеся классы, то для программ, использующих старые классы, ничего не меняется.
Однотипность работы с общей частью - все наследники поддерживают интерфейс базового класса.
Поскольку каждый класс-наследник несет в себе элементы базового класса, то все они будут содержать поля и иметь доступ к методам базового класса.
Например, класс child объявляет себя наследником класса parent:
parent – базовый класс
child – производный класс.
Производный класс унаследует от базового класса все поля данных и почти все методы.
Формат наследования:
сlass имя_базового_класса: доступ имя_производного_класса
{ тело производного класса}
Правила доступа к данным и методам определяет тип наследования:
public, private, protected
Если доступ при наследовании не указан, то действуют стандартные умолчания:
Если используется ключевое слово class - доступ private
для типа struct - доступ public
В данной лабораторной работе рассматривается только public-наследование
Public наследование (правила доступа)
Рассмотрим несколько зон программы:
Базовый класс (Base)
Производный класс (Derived)
Внешняя программа (main)
Доступ к данным базового класса из производного класса
Объявление в Base |
Доступ из Derived |
private |
Недоступны: доступ через методы класса |
protected |
Доступны без посредников |
public |
Доступны без посредников |
Доступ к базовому классу из внешней программы
Объявление в Base |
Доступ из функции main() |
private |
Недоступны: доступ через методы класса |
protected |
Недоступны: доступ через методы класса |
public |
Доступны без посредников |
Доступ к методам
Base – пользователям доступны только Base - методы
Derived - пользователям доступны Derived и Base - методы
Пример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";
w.show();
cout<<"\n--------------------\n";
q.show();
system ("pause");
return 0;
}
Результат выполнения программы:
Характеристики вагона :
Число пассажиров : 39
Грузоподъемность : 50000
Характеристики автомобиля :
Тип : фура
Максимальное число пассажиров : 3
Часто базовый класс (БК) создаётся только для того, чтобы задать общую часть данных для некоторой группы классов. В этом случае функции БК являются вспомогательными («техническими»), они обслуживают нужды «наследников» (в нашем случае – обеспечивают доступ к закрытым данным). В этом случае объектов базового класса не создается.
Конструкторы и деструкторы при наследовании.
При наследовании возникает два вопроса :
• когда вызываются конструкторы и деструкторы базового и производного классов?
• Как передаются параметры конструкторов базового класса?
Как базовый, так и производный классы могут иметь по нескольку конструкторов, поэтому очень важно правильно понимать в каком порядке они вызываются при создании объектов производного класса.
Пример2: Последовательность вызова конструкторов и деструкторов
#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
