Около сорока лет назад большая часть программирования по своей природе была процедурной. Элементами программирования были процедура, функция, алгоритм. Описания данных зачастую были разбросаны по коду программы и не абстрагированы. В объектно-ориентированном программировании базовым понятием выступает понятие объекта, который имеет определенные свойства и располагает набором методов, призванных решать разнообразные задачи.
Главными достоинствами объектно-ориентированного программирования являются: во-первых, использование абстрагирования и инкапсуляции структуры; во-вторых, то, что объекты представляют собой хорошую модель для большинства сущностей реального мира. Вместе с тем иногда становится сложно понять и представить разрабатываемый алгоритм в целом, поскольку его фрагменты могут быть распределены по многим методам, ассоциированным с различными типами объектов.
В настоящее время изучение объектно-ориентированного программирования ведется как в школах (преимущественно используется язык программирования Pascal), так и вузах [1, 2, 3, 7]. Так, в новых учебниках школьного курса информатики изучению объектно-ориентированного программирования выделено особое место [8, 9].
Если при рассмотрении отдельных тем курса объектно-ориентированного программирования можно использовать различные (в том числе достаточно простые) задачи [1, 7], то для демонстрации всей совокупности связей между такими темами желательно подобрать соответствующую задачу.
Ниже приводится пример задачи на реализацию класса «Многочлен», который можно использовать как некоторое обобщение после изучения основных разделов объектно-ориентированного программирования [4].
Сформулируем задачу следующим образом. Требуется описать класс T_Multi (многочлен). Поля класса: имя многочлена, коэффициенты многочлена, корни многочлена. Методы класса: переименование, установка новых параметров многочлена, нахождение корней многочлена, печать многочлена, вывод корней многочлена, печать определенного корня многочлена (по номеру).
Рассмотрим вначале решение задачи без использования механизма перегрузки операций.
Все поля создаваемого класса опишем как private. При этом для хранения сведений о степени многочлена и количестве его корней (на интервале) добавим еще два поля (n и n_sqrt). Функция-утилита No_Sqrt() будет использоваться для задания интервала, на котором будет осуществляться поиск корней, и задания точности нахождения корней.
Конструктор класса будет создавать объект "многочлен" степени 3 и именем "NoName" (параметры по умолчанию). Назначение методов следующее:
- метод Set() позволяет задавать новые параметры многочлена (степень, коэффициенты);
- метод Rename() позволяет изменять имя многочлена;
- метод Sqrt() позволяет определить корни многочлена (аргументы метода задают интервал определения корней и точность их определения), в качестве значения функция возвращает количество корней многочлена на указанном интервале;
- метод Out_IndexSqrt() используется для печати значения определенного корня многочлена (по номеру);
- метод Out_Sqrt() выводит на печать все корни многочлена; единственный аргумент функции используется для перевода строки после вывода значений всех корней (false — перевода строки нет, true — перевод строки есть);
- метод Out() используется для печати многочлена; назначение аргумента функции аналогично рассмотренному выше методу Out_Sqrt().
Реализация перечисленных выше методов понятна из приведенного ниже кода программы, ориентированного на компиляторы Microsoft Visual C++.
По приведенному коду отмечу, что после того, как в программе были указаны новые параметры для многочлена, его корни еще не найдены. Поэтому вызов метода A.Out_Sqrt(1) приводит к вызову функции-утилиты No_Sqrt(), которая вначале запросит интервал для определения корней и точность их определения.
#include "stdafx.h"
#include <iostream>
#include <conio>
#include <math>
using namespace std;
class T_Multi
{ char *Name;
double *a, *sqrt;
int n, n_sqrt;
void No_Sqrt();
public:
T_Multi(int x = 3, char const *y = "No Name");
void Set(int, char const *y = "No Name");
void Rename(char const *y);
int Sqrt(double, double, double);
double Out_IndexSqrt(int);
void Out_Sqrt(bool = 0);
void Out(bool = 0);
~T_Multi(); };
T_Multi::T_Multi(int x, char const *y)
{ n=0; Set(x,y); }
void T_Multi::No_Sqrt()
{ double x,y,z;
cout>x;
cout>y;
cout>z;
Sqrt(x,y,z); }
void T_Multi::Set(int x, char const *y)
{ if (n != 0) delete [] a;
if ((y != "No Name" && n != 0) || (n == 0))
{ if (n != 0) delete [] Name;
Name =new char[strlen(y)+1];
strcpy(Name,y); }
n = abs(x);
a = new double [n+1];
for (int i=0; i>a[i]; }
n_sqrt=0; }
void T_Multi::Rename(char const *y)
{ delete [] Name;
Name =new char[strlen(y)+1];
strcpy(Name,y); }
int T_Multi::Sqrt(double x, double y, double z)
{ int j = 0;
z = (double)fabs(z);
if (n_sqrt != 0) delete [] sqrt;
sqrt = new double [n];
double xx=x+z, s1=0., s2=0., s3=0.;
for(int i=0; i0 && i != 0 && i != n) cout0) cout
На рис. 1. показан результат работы приведенной программы. Для удобства работы необходимо описать еще одну функцию — меню программы. Оставляю это читателю сделать в качестве тренировки самостоятельно.
Рассмотрим теперь этот же пример, но уже с введением в него перегруженных операций. Исходный код программы будет иметь следующий вид.

<pre>#include "stdafx.h"
#include <iostream>
#include <conio>
#include <math>
using namespace std;
class T_Multi
{ char *Name;
double *a, *sqrt;
int n, n_sqrt;
void No_Sqrt();
public:
T_Multi(int x = 3, char const *y = "No Name");
T_Multi & operator () (int, char const *y = "No Name");
T_Multi & operator () (char const *y); //переименование
int operator ()(double, double, double); // поиск корней на интервале
T_Multi & operator ! (); // вывод на печать корней многочлена
double & operator [] (int x); // вывод корня с номером x
T_Multi & operator + (const T_Multi &);
T_Multi & operator = (T_Multi &);
friend ostream & operator > (istream &, T_Multi &);
~T_Multi(); };
T_Multi::T_Multi(int x, char const *y)
{ n=0;
Name =new char[strlen(y)+1];
strcpy(Name,y);
n = abs(x);
a = new double [n+1];
for(int i=0; i>x;
cout>y;
cout>z;
this->operator()(x,y,z); }
T_Multi & T_Multi::operator () (int x, char const *y)
{ if (n != 0) delete [] a;
if ((y != "No Name" && n != 0) || (n == 0))
{ if (n != 0) delete [] Name;
Name =new char[strlen(y)+1];
strcpy(Name,y); }
n = abs(x);
a = new double [n+1];
for (int i=0; i>a[i]; }
n_sqrt=0; return *this; }
T_Multi & T_Multi::operator () (char const *y)
{ delete [] Name;
Name =new char[strlen(y)+1];
strcpy(Name,y);
return *this; }
int T_Multi::operator ()(double x, double y, double z)
{ int j = 0;
z = (double)fabs(z);
if (n_sqrt != 0) delete [] sqrt;
sqrt = new double [n];
double xx=x+z, s1=0., s2=0., s3=0.;
for(int i=0; in;
if (y 0 && i != 0 && i != d.n)
out0)
out> (istream &in, T_Multi &d)
{ for(int i=0; i>d.a[i]; }
return in;}
T_Multi::~T_Multi()
{ delete [] Name;
delete [] a;
if (n_sqrt != 0) delete [] sqrt; }
int main()
{ setlocale(LC_ALL,"Rus");
T_Multi A(3,"Multi A"), B(1,"Multi B"), C(2,"Multi C");
cout>A;
cout>B;
cout
В приведенном коде операция () перегружена несколько раз, и используется для ввода значений коэффициентов многочлена, переименования многочлена и поиска его корней на заданном интервале.
Таким образом, рассмотренная в статье задача позволяет продемонстрировать основные идеи использования методов классов, а также показывает некоторые реализации перегруженных операций.
В заключение отмечу, что в плане проверки уровня усвоения учащимися учебного материала может оказаться удобным использование всевозможных программ-тестов [5, 6]