Конструкторы и деструкторы при наследовании
Следующий список показывает последовательность шагов при конструировании производного класса:
1) Вызывается конструктор базового класса.
2) Вызывается конструктор тех элементов, которые являются объектами какого-либо класса, в том порядке, в котором производный класс их объявляет.
3) Исполняется тело конструктора производного класса.
Деструкция производного класса выполняется в порядке, обратном конструированию:
1) Вызывается деструктор производного класса.
2) Вызываются деструкторы элементов, являющихся объектами классов.
3) Вызывается деструктор базового класса.
22.6 Абстрактные классы и чистые виртуальные функции
Абстрактным является класс, в котором есть хотя бы одна чистая виртуальная функция. Напомним ее вид:
virtual тип_результата имя_функции()=0
Она может рассматриваться как встроенная (inline-функция), тело которой определено как =0 (чистый спецификатор). Чистая виртуальная переопределяется в производных классах. Другими словами, в абстрактном классе только объявляются функции с определенными именами, а конкретное содержание того, что будут делать эти функции, будет определено в производных классах. Ясно, что из-за этого абстрактный класс может использоваться только в качестве базового для других классов. К абстрактным классам применимы следующие правила:
1 Абстрактный класс не может использоваться в качестве аргумента функции или типа возвращаемого результата.
2 Абстрактный класс нельзя использовать в явном преобразовании.
3 Нельзя определить объект абстрактного класса (глобальную/локальную переменную или элемент данных).
4 Можно определять указатель или ссылку на абстрактный класс.
5 Если класс, производный от абстрактного, не определяет все чистые виртуальные функции абстрактного класса, он также является абстрактным.
Рассмотрим пример. У плоской фигуры есть общие элементы данных: периметр(perimetr) и площадь(plo). Есть конкретные плоские фигуры: прямоугольник (rectangle) и круг (crug). Для каждой из этих фигур имеются свои элементы-данные и по-разному вычисляются периметр (длина окружности для круга) и площадь. При программировании удобно, чтобы члены функции ввода/вывода данных, а также функции вычисления периметра и площади имели одинаковые имена как при работе с прямоугольником, так и при вычислении параметров круга. Сделаем class fiqure базовым. В нем опишем чистые виртуальные функции для ввода, вывода данных, вычисления периметра и вычисления площади. Определим два производных класса: class crug и class rectangle. В них будут переопределены чистые виртуальные функции.
#include<stdio.h>
#include<math.h>
class fiqure
{
protectrd:
float perimeter, plo;
public:
virtual void input()=0;//Ввод данных
virtual void output()=0;//Вывод результатов
virtual void l()=0;//Вычисление периметра
virtual void s()=0;// Вычисление площади
}
class crug: public fiqure
{
float R; //Радиус
public:
void input()//virtual можно не писать
{
puts(“Введите радиус”)
scanf(“%f, &R);
}
void output()
printf(“Для круга длина окружности (perimetr)=%f, площадь=%f\n”, perimetr, plo);
}
void l()
{
perimeter=2*M_PI*R;
}
void s()
{
plo =M_PI*R*R
}
};
class reet: public fiqure
{
float a,b;//ширина и длина
public:
void input()
{
puts(“Введите а и в”);
scanf(“%f%f, &a, &b);
}
void output()
{
printf(“Для прямоугольника периметр=%f площадь =%f \n”perimetr, plo);
}
void l()
{
perimetr =2*(a+b);
}
void s()
{
plo =a*b;
}
};
void main()
{
fiqure*p=new crug;/*В указатель р на базовый класс заносится адрес, выделенный под объект производного класса crug*/
p→input();
p→l();
p→s();
p→output();/*Последовательно вызываются функции класса crug*/
p=new rectangle;
p→input();
p→l();
p→s();
p→output();
}
После занесения в указатель р адреса для объекта класса rectangle происходит вызов соответствующих виртуальных функций класса rectangle.
Лекция 23
23.1 Классы потоков языка С++
Библиотека потоков С++ (библиотека iostream) представляет набор классов для управления вводом/выводом. Эти классы имеют несколько преимуществ по сравнению с традиционными средствами ввода/вывода (i/o):
· Надежность. Семейства функций printf и scanf не предусматривают никакой проверки типа. Компилятор не может сигнализировать о несоответствии спецификаций формата передаваемым аргументам. Механизм потоков С++ основывается на перегрузке функций (операций), что обеспечивает для каждого типа передаваемых данных вызов соответствующей функции.
· Расширяемость. Применение процедур С ограничено файловыми потоками (и некоторыми устройствами, доступ к которым возможен как к предопределенным потокам). Эти процедуры допускают расширения. Классы С++, благодаря полиморфизму, позволяют одним и тем же процедурам работать с потоками различных типов. Например, тот же интерфейс, что используется стандартным вводом/выводом, применим к файловым и резидентным потокам. Можно предусмотреть собственные перегруженные функции, которые позволят библиотеке потоков С++ работать с определяемыми пользователем типами.
· Простота и последовательность. Широкое использование перегруженных функций позволяет библиотеке потоков поддерживать единообразный интерфейс ввода/вывода. Это приводит к более простому и понятному синтаксису.
Заголовочные файлы
Чтобы обеспечить программе доступ к библиотекам потоков С++, нужно включить в нее заголовочный файл iostream.h. При файловом вводе/выводе следует включить также fstream.h и iomanip.h (манипуляторы).