Virtual тип_возврата имя_функции

(список_параметров) = 0;

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

Можно создавать указатели и ссылки на абстрактный класс. Это позволяет применять абстрактные классы для поддержки динамического полиморфизма и выбирать соответствующую виртуальную функцию в зависимости от типа объекта.

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

Абстрактный класс нельзя использовать при явном приведении типов, для описания типа параметра функции (передаваемого по значению) и типа возвращаемого функцией значения.

Рассмотрим пример программы: система расчета заработной платы.

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

 

Базовым классом является класс Employee – служащие организации. Производными классами от базового класса Employee являются класс Boss – служащие, которым начисляется еженедельный фиксированный оклад и класс PieceWorker – служащие, которым начисляется сдельная заработная плата по количеству изготовленных изделий. Вызов функции начисления заработной платы earnings используется для всех служащих. Но способы, которыми начисляется заработная плата, зависят от классов служащих.

 

Класс Employee включает следующие открытые функции-элементы:

· конструктор без параметров;

· конструктор, который принимает в качестве аргумента фамилию;

· деструктор, который высвобождает динамически выделенную память;

· функцию доступа getName, которая возвращает фамилию;

· функцию изменения фамилии;

· три чисто виртуальные функции earnings, print и vvod.

 

Класс Boss является производным от класса Employee с открытым наследованием. Открытые функции-элементы включают:

· конструктор без параметров;

· конструктор, который принимает в качестве аргументов фамилию и еженедельный оклад, а также передает фамилию конструктору Employee для инициализации элемента Name той части объекта производного класса, которая совпадает с базовым классом;

· функцию set, которая присваивает новое значение скрытому элементу данных weekSalary;

· виртуальную функцию earnings, в которой определено, как начислять заработную плату в классе Boss;

· виртуальную функцию print, которая выводит тип служащего и его фамилию;

· виртуальную функцию vvod, с помощью которой вводится фамилия служащего и его оклад.

 

Класс PieceWorker является производным от класса Employee с открытым наследованием. Открытые функции-элементы включают:

· конструктор без параметров;

· конструктор, который принимает в качестве аргументов фамилию, оплату за единицу продукции и количество произведенной продукции за неделю, а также передает фамилию конструктору Employee;

· функцию set, которая присваивает новые значения скрытым данным-элементам wagePerPiece и quantity;

· виртуальную функцию earnings, в которой определено, как начислять заработную плату в классе PieceWorker;

· виртуальную функцию print, которая выводит тип служащего и его фамилию;

· виртуальную функцию vvod, которая вводит фамилию служащего, оплату единицы продукции и число единиц продукции.

 

В программе определены также две независимые внешние функции:

· функция ввода (перегруженная операция >>);

· функция вывода (перегруженная операция <<).

Данные функции не являются дружественными. Им передаются два параметра: первый параметр – ссылка на поток, а второй – ссылка на базовый класс, а вызывается операция с параметрами производных типов.

Для этих функции используется следующий прием виртуализации внешней функции. В базовом классе объявляется чистая виртуальная функция-метод, а в производных классах реализуется ее определение. Внешней независимой функции передается параметр базового класса, для которого и вызывается базовая виртуальная функция.

 

// Листинг 19.1

#include <iostream>

#include <fstream>

#include <cstdlib>

#include <cstring>

using namespace std;

 

// Абстрактный класс

class Employee

{

char * Name; //фамилия служащего

public:

Employee();

Employee(const char *);

~Employee();

const char * getName();

void setName(const char *);

 

// Чисто виртуальные функции

virtual double earnings() = 0;

virtual ostream& print(ostream &)=0;

virtual istream& vvod(istream &)=0;

};

 

//Конструктор без параметров

Employee::Employee()

{Name=0;}

 

//Конструктор динамически выделяет память

//для фамилии и использует функцию strcpy

//для копирования ее в объект

Employee::Employee(const char * fam) {

Name = new char [strlen(fam) + 1];

strcpy(Name, fam);

}

 

//Деструктор высвобождает

//динамически выделенную память

Employee::~Employee() {

delete [] Name;

}

 

// Возвращение указателя на фамилию

const char * Employee::getName()

{

//const препятствует модификации скрытых данных

// со стороны вызывающей программы

return Name;

}

 

//смена фамилии служащего

void Employee::setName(const char *fam)

{ if(Name!=0) delete [] Name;

Name = new char [strlen(fam) + 1];

strcpy(Name, fam);

}

 

// Класс Boss, производный от класса Employee

class Boss: public Employee

{

//фиксированная зар.плата за неделю

double weeklySalary;

public:

Boss();

Boss(const char *, double = 0.0);

void setWeeklySalary(double);

virtual double earnings();

virtual ostream& print(ostream &);

virtual istream& vvod(istream &);

};

 

// Конструктор класса Boss без параметров

Boss::Boss():Employee()

{setWeeklySalary(0.);}

 

//Конструктор класса Boss с параметрами

Boss::Boss(const char * fam, double s)

:Employee(fam)

{ setWeeklySalary(s); }

 

//Установка еженедельного оклада

//для класса Boss

void Boss::setWeeklySalary(double s)

{ weeklySalary = s; }

 

// Начисление заработной платы в классе Boss

double Boss::earnings() {

return weeklySalary;

}

 

// Вывод фамилии служащего из класса Boss

ostream& Boss::print(ostream &t) {

t<<"\nАдминистратор: "<<getName()<<" ";

return t;

}

 

//Ввод информации о служащем

//с фиксированной зар.платой

istream& Boss::vvod(istream &t)

{ char fam[20];

t>>fam;

setName(fam);

t>>weeklySalary;

return t;}

 

// Класс PieceWorker, производный от Employee

class PieceWorker: public Employee

{// оплата единицы продукции

double wagePerPiece;

// число единиц продукции за неделю

unsigned quantity;

public:

PieceWorker();

PieceWorker(const char *, double = 0.0,

unsigned = 0);

void setWage(double);

void setQuantity(unsigned);

virtual double earnings();

virtual ostream& print(ostream &);

virtual istream& vvod(istream &);

};

 

//Конструктор класса PieceWorker без параметров

PieceWorker::PieceWorker():Employee()

{ wagePerPiece =0.;

quantity = 0;

}

 

// Конструктор класса PieceWorker с параметрами

PieceWorker::PieceWorker(const char * f,double w, unsigned q):Employee(f)

{ wagePerPiece = w;

quantity = q;

}

 

// Установка стоимости единицы продукции

void PieceWorker::setWage(double w)

{ wagePerPiece = w; }

 

// Установка количества единиц произведенной продукции

void PieceWorker::setQuantity(unsigned q)

{ quantity = q; }

 

// Определение заработной платы

double PieceWorker::earnings()

{ return quantity*wagePerPiece; }

 

//Вывод фамилии служащего

//из класса PieceWorker

ostream& PieceWorker::print(ostream &t)

{ t << "\n" <<"Служащий на сдельной оплате: "<< getName() << " ";

return t;

}

 

//Ввод информации

//о служащем со сдельной зар.платой

istream& PieceWorker::vvod(istream &t)

{ char fam[20];

t>>fam;

setName(fam);

t>>wagePerPiece;

t>>quantity;

return t;}

 

inline ostream& operator<<(ostream &t,Employee &r)

{return r.print(t);}

 

inline istream& operator>>(istream &t,Employee &r)

{return r.vvod(t);}

 

 

int main()

{

//Установка поддержки русского языка

// в Visual Studio

setlocale(LC_CTYPE,"Russian");

 

Employee *ptr; // указатель базового класса

Boss b("Иванов", 800.0);

// указатель базового класса

// на объект производного класса

ptr = &b;

 

// динамическое связывание

cout<<*(ptr);

cout << "заработал " << ptr->earnings() << endl;

 

// статическое связывание

cout<<b;

cout << "заработал " << b.earnings() << endl;

 

PieceWorker p("Попов", 2.5,200);

// указатель базового класса

//на объект производного класса

ptr = &p;

 

// динамическое связывание

cout<<*(ptr);

cout << "заработал " << ptr->earnings()<< endl;

 

// статическое связывание

cout<<p;

cout << "заработал " << p.earnings()<< endl;

 

cout << endl<<"Массив указателей базового типа"<< endl;

Employee * mas[5];

//заполним массив указателей адресами //создаваемых объектов производных классов

//в файле file1.txt содержится информация

//о сотрудниках с фиксированным окладом

//открытие файла для ввода

ifstream inarray("file1.txt");

if(!inarray)

{cout<<"File can not be open\n";

exit(1);}

//ввод информации из файла

for(int i=0;i<3;i++)

{ mas[i]=new Boss;

inarray>>*(mas[i]);

}

 

//в файле file2.txt содержится информация

//о сотрудниках со сдельной зар.платой

//открытие файла для ввода

ifstream inarray1("file2.txt");

if(!inarray)

{cout<<"File can not be open\n";

exit(1);}

//ввод информации из файла

for(int i=3;i<5;i++)

{ mas[i]=new PieceWorker;

inarray1>>*(mas[i]);

}

 

 

//открытие файла для вывода

ofstream outarray("result.txt");

if(!outarray)

{cout<<"File can not be open\n";

exit(1);}

for (int i = 0; i < 5; ++i) {

//вывод информации на экран

cout<<*(mas[i])<<" заработал " << mas[i]->earnings()<< endl;

//вывод информации в файл

outarray<<*(mas[i])<<" заработал "<< mas[i]->earnings()<< endl;

}

inarray.close();

inarray1.close();

outarray.close();

return 0;

}

Результаты выполнения программы:

 

Пусть в файле file1.txt содержитсяинформация:

Антипов 456.8

Филатов 656.6

Парамонов 879.7

 

Пусть в файле file2.txt содержитсяинформация:

Зубов 56 10

Дубов 38 20

 

На экран будет выведена информация:

Администратор: Иванов заработал 800

Администратор: Иванов заработал 800

Служащий на сдельной оплате: Попов заработал 500

Служащий на сдельной оплате: Попов заработал 500

Массив указателей базового типа

Администратор: Антипов заработал 456.8

Администратор: Филатов заработал 656.6

Администратор: Парамонов заработал 879.7

Служащий на сдельной оплате: Зубов заработал 560

Служащий на сдельной оплате: Дубов заработал 760

 

Содержимое файла result.txt:

Администратор: Антипов заработал 456.8

Администратор: Филатов заработал 656.6

Администратор: Парамонов заработал 879.7

Служащий на сдельной оплате: Зубов заработал 560

Служащий на сдельной оплате: Дубов заработал 760

 

Задание:

Написать программу на языке С++ согласно варианту.

В программе должны быть перегружены операции >> и <<.

Создать текстовый файл objects.txt, содержащий информацию об объектах производных классов (в одном файле хранится информация об объектах разных классов).

Сформировать массив указателей на абстрактный базовый класс. Заполнить элементы массива адресами создаваемых объектов производных классов на основе информации, считываемой из файла objects.txt.

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

Создать многофайловый проект.

 

Вариант 1

Создать абстрактный класс Body (тело) с виртуальными методами вычисления площади поверхности и объема. Создать производные классы Parallelepiped (параллелепипед) и Ball (шар).

 

Вариант 2

Создать абстрактный класс Currency (валюта) с виртуальными методами для работы с денежными суммами. Создать производные классы Dollar (доллар) и Euro (евро).

 

Вариант 3

Создать абстрактный класс Norm с виртуальными методами вычисления нормы и модуля. Создать производные классы Complex, Vector3D. Модуль для комплексного числа вычисляется как корень из суммы квадратов действительной и мнимой частей; норма для комплексных чисел вычисляется как модуль в квадрате. Модуль вектора вычисляется как корень квадратный из суммы квадратов координат; норма вектора вычисляется как максимальное из абсолютных значений координат.

 

Вариант 4

Создать абстрактный класс Function (функция) с виртуальными методами вычисления значения функции y = f (x) в заданной точке x и вывода результата на экран. Создать производные классы Ellipse (эллипс) и Hyperbola (гипербола). Уравнение эллипса ; гиперболы: .

 

Вариант 5

Создать абстрактный класс Figure c виртуальными методами вычисления площади и периметра. Создать производные классы Rectangle (прямоугольник), Circle (круг), Trapezium (трапеция).

 

Вариант 6

Создать абстрактный класс Series (прогрессия) с виртуальными методами вычисления j -го элемента прогрессии и суммы n членов прогрессии. Создать производные классы Linear (арифметическая) и Exponential (геометрическая). Арифметическая прогрессия Сумма арифметической прогрессии: Геометрическая прогрессия: Сумма геометрической прогрессии: .

 

Вариант 7

Создать абстрактный класс Root (корень уравнения) с виртуальным методом вычисления корней. Создать производные классы Linear (линейное уравнение) и Square (квадратное уравнение).

 

Вариант 8

Создать абстрактный класс Triad с тремя целочисленными полями и виртуальными методами увеличения на 1 значений полей класса. Создать производные класс Time (время) с полями час, минута, секунда и класс Date (дата) с полями год, месяц, день.

 

Вариант 9

Создать абстрактный класс Detail (деталь) с членами: материал детали (определяющий стоимость единицы веса), вес и с виртуальными методом вычисления стоимости детали. Создать производные классы Box (короб) и Handle (ручка).

 

Вариант 10

Создать абстрактный класс Triangle (треугольник) с виртуальными методами вычисления площади и периметра треугольника. Создать производные классы прямоугольный треугольник, равнобедренный треугольник, равносторонний треугольник.

 

Вариант 11

Создать абстрактный класс Calculation (вычисление) с виртуальными методами вычисления значения функции y = f (x) в заданной точке x и вывода результата на экран. Создать производные классы Sinus (синус ) и Parabola (парабола ).

 

 

Вариант 12

Создать абстрактный класс Flash (тело) с виртуальными методами вычисления площади поверхности и объема. Создать производные классы Conus (конус) и Cilinder (цилиндр).

 

Вариант 13

Создать абстрактный класс Modul с виртуальным методом вычисления модуля. Создать производные классы Complex (комплексное число), Fraction (дробь). Модуль комплексного числа вычислять как корень из суммы квадратов действительной и мнимой частей; модуль дроби вычислять как корень квадратный из суммы квадратов числителя и знаменателя.

 

Вариант 14

Создать абстрактный класс Changemas (изменяемый массив) с виртуальными методами сортировки и поэлементной обработки массива. Создать производные классы Bubble и Choice. В классе Bubble сортировка реализуется методом пузырька, а поэлементная обработка состоит в извлечении квадратного корня. В классе Choice сортировка реализуется методом выбора, а поэлементная обработка – вычисление натурального логарифма.

 

Вариант 15

Создать абстрактный класс Pay (плата) с виртуальным методом вычисления стоимости оплаты. Создать производные классы Flat (квартира) и Phone (телефон).

 

 

Вариант 16

Создать абстрактный класс Processing (обработка) с виртуальными методом обработки объекта. Создать производные классы Array (массив чисел) и String (строка символов). В классе Array обработка реализует домножение каждого элемента массива на среднее, а в классе String – замену всех букв на заглавные.

 


РЕКОМЕНДУЕМАЯ ЛИТЕРАТУРА

 

1. Березин Б.И., Березин С.Б. Начальный курс С и С++. – М.: Диалог-МИФИ, 2012. – 288 с.

2. Дейтел Х.М., Дейтел П.Дж. Как программировать на С++. –М.: Бином-Пресс, 2011. – 1456 с.

3. Клюшин Д.А. Полный курс C++. Профессиональная работа. – М.: Издательский дом «Вильямс», 2004. – 672 с.

4. Лаптев В.В. С++. Объектно-ориентированное програм-мирование. Учебное пособие. – СПб.: Питер, 2008. – 464 с.

5. Лаптев В.В., Морозов А.В., Бокова А.В. С++. Объектно-ориентированное программирование. Задачи и упражнения. – Спб.: Питер, 2007. – 288 с.

6. Мэтью Н., Стоунс Р. Основы программирования в Linux. – СПб.: БХВ-Петербург, 2009. – 896 с.

7. Павловская Т.А. С/С++. Программирование на языке высокого уровня. Учебник. – СПб.: Питер, 2013. – 464 с.

8. Павловская Т.А., Щупак Ю.А. С/С++. Структурное и объектно-ориентированное программирование. Практикум. – СПб.: Питер, 2011. – 352 с.

9. Подбельский В.В. Стандартный Си++. Учебное пособие. – М.: Финансы и статистика, 2008. – 688 с.

10. Прата С. Язык программирования С++. Лекции и упражне­ния. – М.: Издательский дом «Вильямс», 2012. – 1244 с.

11. Страуструп Б. Программирование: принципы и практика использования С++. – М.: Издательский дом «Вильямс», 2011. – 1238 с.

12. Хортон А. Visual C++ 2010. Полный курс. – М.: Издательский дом «Вильямс», 2011. – 1206 с.

13. Шилдт Г. C++: базовый курс. – М.: Издательский дом «Вильямс», 2012. – 624 с.

14. Шилдт Г. Полный справочник по C++. – М.: Диалектика, Вильямс, 2012. – 795 с.

15. Штерн В. С++. Методы программной инженерии. –М.: Лори, 2013. – 860 с.

 

 

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: