Конструкторы и деструкторы при наследовании

Следующий список показывает последовательность шагов при конструировании производного класса:

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 (манипуляторы).

Наши рекомендации