- •Д. Н. Лясин, с. Г. Саньков
- •Оглавление
- •1.Обзор стилей программирования
- •1.1. Процедурное программирование
- •Структурное программирование
- •Функциональное программирование
- •Логическое программирование
- •1.5. Объектно-ориентированное программирование
- •Основные принципы объектно-ориентированного программирования
- •3.1. Объявление классов и объектов
- •3.2. Конструкторы и деструкторы
- •3.3. Область видимости компонент класса
- •3.4. Определение компонентных функций класса
- •3.5. Статические компоненты классов
- •Дружественные функции
- •3.7. Перегрузка операций
- •4. Наследование классов
- •4.1. Повторное использование классов: наследование и агрегирование
- •4.3. Множественное наследование
- •4.4. Виртуальные классы
- •4.5. Виртуальные функции. Полиморфизм
- •4.6. Абстрактные классы
- •Список литературы
3.1. Объявление классов и объектов
Класс – это определяемый пользователем тип данных, описывающий с точки зрения объектно-ориентированного программирования некоторый объект из предметной области решаемой задачи. Объект – это экземпляр класса, переменная типа, описываемого классом. Таким образом, разница между понятиями класс и объект схожа с разницей между понятиями «тип данных» и «экземпляр типа». Объект существует в памяти, класс же является шаблоном, по которому создается объект.
Определение класса в программе можно сделать одним из трех способов с использованием ключевых слов class, struct или union:
сlass имя класса { список членов};
struct имя класса { список членов};
union имя класса { список членов};
Здесь имя класса – имя определяемого пользовательского типа данных, список членов – список свойств и методов класса, сделанных согласно синтаксису языка С++. Различия между тремя представленными объявлениями класса заключаются, во-первых, в разных правах доступа, присваиваемых компонентам класса по умолчанию, а также в способе расположения компонент класса в памяти. Для классов, объявленных с использованием ключевых слов srtuct и union, компоненты класса по умолчанию являются доступными для окружения. Для классов, объявленных через class, компоненты по умолчанию недоступны вне класса.
Рассмотрим пример объявления класса, описывающего работу с одномерным массивом целых чисел.
//Листинг 1. Определение класса – «массив целых чисел»
struct array
{ int *mas; // указатель на начало массива
int n; //количество элементов в массиве
void InitMas(int k) //функция инициализации - выделения динамической памяти
//под массив
{if (k>0)
{n=k;
mas=new int[n];
}}
void DelMas() //функция уничтожения массива
{n=0;
delete []mas;
}
void ReadMas() //функция ввода массива в клавиатуры
{ cout<<"Вывод массива";
for (int i=0;i<n;i++)
cin>>mas[i];
}
void WriteMas() //функция вывода элементов массива на экран
{ cout<<"Вывод массива";
for (int i=0;i<n;i++)
cout<<mas[i];
cout<<'\n';
}};
В определении класса описаны два компонентных члена данных: n и mas. Они хранят некоторые значения, описывающие параметры класса-массива. Также в классе определены компонентные функции или методы класса: InitMas, DelMas, ReadMas и WriteMas, назначение которых – обрабатывать данные, хранящиеся в членах данных класса. Согласно принципу инкапсуляции, методы класса являются его интерфейсной частью, посредством использования этих методов необходимо работать с массивом. Набор методов класса невелик, он позволяет лишь выделять и освобождать динамическую память под массив, а также вводить с клавиатуры и выводить на экран значения элементов массива. Расширить набор методов, например, функциями сортировки массива или поиска максимума или минимума читатель сможет самостоятельно. Теперь рассмотрим пример использования определенного выше класса.
//Листинг2. Пример использования объектов класса «массив целых чисел»из листинга 1
main()
{ array m,m1;
m.InitMas(4);
m1.InitMas(5);
m.ReadMas();
m.WriteMas();
m1.ReadMas();
m1.WriteMas();
m1.DelMas();
m.DelMas();
}
Общий синтаксис определения объекта класса не отличается от определения обычной переменной:
имя_класса имя_объекта;
В приведенном примере сначала определяются два объекта класса array с именами m и m1. При этом в памяти выделяется по 6 байт на каждый объект: 2 под n и 4 под mas (при условии использования far указателей). При создании объекта память выделяется только под компонентные данные, методы класса существуют в памяти в единственном экземпляре и все объекты используют их совместно. Далее для каждого из объектов вызываются методы класса. Обращение к методам и компонентным данным возможно через имя уже определенного объекта по следующему синтаксису:
имя_объекта.имя_члена_данных
имя_объекта.имя_метода(список_фактических_параметров)
Необходимо отметить, что метод класса нельзя вызвать независимо от объекта. Если рассмотреть, например, тело функции InitMas, то можно заметить, что эта функция изменяет значения компонентных данных n и mas. Однако нигде внутри тела метода не определяется, с компонентами какого именно объекта должна работать функция. Очевидно, что в теле класса это и невозможно определить, поскольку данный метод будет обрабатывать компонентные данные различных объектов. Привязка метода класса к конкретному объекту осуществляется в момент вызова метода. Компонентные функции при их вызове неявно получают дополнительный аргумент - указатель на переменную объектного типа, для которой вызвана функция, и в теле функции можно обращаться ко всем компонентам объекта. Так, например, для вызова m.InitMas(4) компонентная функция InitMas будет работать с компонентами объекта m, а для вызова m1.InitMas(5)- с компонентами объекта m1.
Память под объект можно выделять динамически, что иллюстрируется следующим примером:
//Листинг3. Обращение к компонентам класса при динамическом выделении памяти
//под объект
main()
{ array *ptm;
ptm=new array;
ptm->InitMas(4); //можно также (*ptm).InitMas(4)
ptm->ReadMas();
ptm->WriteMas();
prm->DelMas();
}