Знакомство с классами
Понятие класса
Инкапсуляция - механизм, позволяющий объединять в едином объекте множество его характеристик (данные, характеризующие объект) и действий над ними (средства обработки этих данных).
Сокрытие представляет собой принцип разграничения доступа различных частей программы к различным элементам данных и действий над ними.
В языке С++ классы соединяют в себе оба эти понятия, позволяя в одном объекте объединять различные его характеристики (переменные) и средства их обработки (функции), а также обладают средствами разграничения доступа к различным частям объектов из разных частей программы.
Класс – это тип данных, определяемый пользователем. Класс может содержать определение только данных или только некоторых действий, но чаще всего он содержит и то, и другое.
Данные (переменные), характеризующие класс, называются членами данных, а действия над ними (функции) – функциями-членами класса.
Для работы с некоторым классом создаются переменные этого типа, называемые экземплярами класса.
Определение класса осуществляется с помощью инструкции class:
class <идентификатор класса>
{
// Закрытые члены класса
public:
// Открытые члены класса
} <список экземпляров класса>;
Например:
typedef double t_Inf; //Тип данных элементов массива
const t_Inf DefVal = 0; //Значение элемента массива по умолчанию
char Err [] = "\n***В массиве нет элемента с индексом "; //Сообщение об ошибке
class t_DinArr {
// Закрытые члены-данные класса
t_Inf * Arr; //Указатель на динамический массив
unsigned ItemCount; //Количество элементов в массиве
public:
// Открытые члены-функции класса
void Init (unsigned N = 0); //Инициализация массива из N элементов
void Clear(); //Очистка массива
void Set (unsigned Ind, t_Inf Val); //Запись значенияVal в элемент с индексом Ind
t_Inf Get (unsigned Ind); //Возвращает значение элемента с индексом Ind
void Add ( t_Inf Val ); //Добавляет в конец массива элемент со значением Val
unsigned Count (); //Возвращает количество элементов массива
void Free (); //Удаление массива из динамической памяти
} ;
В этом примере начато создание класса для работы с одномерными динамическими массивами. Элементами этого массива являются данные типа t_Inf (в этом примере – эквивалент типаdouble). Константа DefVal = 0 определяет значение элементов массива по умолчанию.
Идентификатор класса t_DinArr определяет новый пользовательский тип данных, включающий в себя два члена-данных: Arr(указатель на массив элементов типа t_Inf) и ItemCount (переменная, определяющая текущее количество элементов массива). И Arr и ItemCount являются закрытыми членами класса (все члены класса, расположенные до слова public, являются закрытыми). После слова public перечисляются открытые члены класса. В нашем примере это пять членов-функций. Функция Initсоздает динамический массив на N элементов и инициализирует его элементы значениямиDefVal. Функция Setприсваивает элементу массива с индексом Ind значение Val. Функция Get возвращает значение элемента массива с индексом Ind. Функция Countвозвращаетколичество элементов массива. Функция Free удаляет массив из динамической памяти. Члены-функции определяются с помощью прототипов. Реализация этих функций приведена ниже. Таким образом, класс инкапсулирует два члена-данных и пять функций членов.
Различие между закрытыми и открытыми членами класса состоит в следующем. К закрытым членам класса могут обращаться только другие члены класса (открытые и закрытые). Открытые члены класса доступны везде (и в других членах класса, и в программе). Иными словами, при использовании некоторого класса программист в программе может пользоваться только открытыми членами класса. Закрытые члены класса могут использоваться только внутри реализации класса. Определяя Arrи ItemCount закрытыми, мы осуществляем сокрытие этих данных от прямого доступа к ним. При использовании этого класса в программе программист не может напрямую изменять эти данные, что предотвращает возможность возникновения ошибок при работе с массивом. Например, если сделать Arr открытым членом класса, то в программе можно будет напрямую изменить значение указателя на первый элемент массива, присвоив ему, например, значение 0. В этом случае уже имеющийся в динамической области памяти массив будет «потерян» - произойдет утечка памяти. Этого допускать нельзя. То же самое касается и члена класса ItemCount – произвольные изменения его значения могут привести к неправильной работе программы.
Перейдем к реализации членов функций.
Член функцию Init можно реализовать так:
void t_DinArr :: Init (unsigned N) //Инициализация массива из N элементов
{
if (N) //ЕслиNбольше0
//Выделяем память в динамической области дляN элементов массива
Arr = (t_Inf *) malloc ( sizeof(t_Inf) * N );
Else
//ПриN = 0указатель на массив равен0 –массива нет
Arr = 0;
//Устанавливаем значение количества элементов в массиве
ItemCount = N;
//Очищаем массив значениями DefVal
Clear();
}
В чем особенности определения:
1. Для того, чтобы показать, что функцияInit является членом классаt_DinArr, перед ее именем необходимо указать префикс t_DinArr ::.
2. Обращение и к открытым, и к закрытым членам класса внутри тела функции осуществляется напрямую
Аналогичным образом реализуются и остальные функции члены класса:
void t_DinArr : : Clear () //Очистка массива значениями DefVal
{
for (unsigned i = 0; i < ItemCount; ++ i)
Arr [i] = DefVal;
}
//Запись значенияVal в элемент с индексом Ind
void t_DinArr : : Set(unsigned Ind, t_Inf Val)
{
if (Ind >= ItemCount) //Индекс выходит за границу массива
cout << Err << Ind << '!\n'; //Выводим сообщение об ошибке
else //Индекс правильный
Arr [Ind] = Val; //Элементу массива с индексом Ind присваиваем значениеVal
}
//Возвращает значение элемента с индексом Ind
t_Inf t_DinArr : : Get(unsigned Ind)
{
if ( Ind >= ItemCount ) //Индекс выходит за границу массива
{
cout << Err << Ind << "!\n"; //Выводим сообщение об ошибке
return DefVal; //Возвращаем из функции значениеDefVal
}
else //Индекс правильный
return Arr [ Ind ]; //Возвращаем из функции значение элемента с индексом Ind
}
//Добавляет в конец массива элемент со значением Val
void t_DinArr : : Add(t_Inf Val)
{
++ ItemCount; //Количество элементов в массиве увеличиваем на 1
//Увеличиваем размер массива до нового количества элементов
Arr = ( t_Inf * ) realloc ( Arr, sizeof(t_Inf) * ItemCount );
//В новый (последний) элемент массива записываем значениеVal
Arr [ ItemCount – 1 ] = Val;
}
unsigned t_DinArr : : Count ( ) //Возвращает количество элементов массива
{
Return ItemCount;
}
void t_DinArr : : Free ( ) //Удаление массива из динамической памяти
{
if (Arr) //Указатель на массив не равен0 –массив есть
{
free(Arr); //Освобождаем динамическую память
Arr = 0; //Делаем указатель на массив равным0 –массива нет
ItemCount = 0; //Присваиваем количеству элементов в массиве значение0
}
}
Первый вариант класса t_DinArr готов. Его использование иллюстрируется следующим примером:
Int main ( )
{
setlocale ( 0, "" );
//Описываем экземпляр класса (статическая переменная DA типа t_DinArr):
T_DinArr DA;
//Вводим с клавиатуры необходимый размер массива:
Unsigned N;
cout << “Количество элементов в массиве: ”;
cin >> N;
// Инициализируем экземпляр класса (при этом в динамической области
// памяти будет создан массив на заданное количество элементов
// и этот массив будет «обнулён» значениями DefVal):
DA.Init ( N );
// В цикле заполняем созданный массив некоторыми значениями, например,
// равными индексам элементов массива:
for ( unsigned i = 0; i < DA.Count ( ); ++ i )
DA.Set ( i, i );
// Для контроля выводим на экран значения элементов массива:
for ( unsigned i = 0; i < DA.Count ( ); ++ i )
cout << DA.Get ( i ) << ‘ ‘;// на экране видим числа:0 1 2 … N-1
cout << endl;
// В цикле добавляем в конец массива еще 5 элементов, информационные части
// которых заполняются значениями, от N до N + 4
for ( unsigned i = 0; i < 5; ++ i )
DA.Add ( N + i );
// Снова для контроля выводим на экран значения элементов массива:
for ( unsigned i = 0; i < DA.Count ( ); ++ i )
cout << DA.Get ( i ) << ‘ ‘;// на экране видим числа:0 1 2 … N + 4
cout << endl;
// Заканчиваем работу с массивом (освобождаем динамическую память):
DA.Free ( );
system ( "pause" );
Return 0;
}
Обсудим использование класса в этом примере.
- Обращение к членам экземпляра класса осуществляется точно так же, как и к полям обычных структур, с помощью оператора «точка», например: DA.Init ( N ).
- В функции main обращаться можно только к открытым членам класса. Доступ к закрытым членам класса (Arr и ItemCount) осуществляется опосредованно через функции члены класса, что защищает программу от случайных возможно ошибочных изменений этих данных.
- Для работы с массивом необходимо перед началом работы объявить экземпляр класса (t_DinArr DA;) и инициализировать его (DA.Init ( N );).
- При окончании работы с экземпляром класса необходимо освободить динамическую память (DA.Free ( );).
Рабочая программа этого примера приведена в Приложении 1.
Дата добавления: 2019-02-07; просмотров: 232;