Язык С++ позволяет создавать собственные типы данных, которые ведут себя аналогично базовым типам языка Си. Такие типы обычно называют абстрактными типами данных (АТД).
Для реализации АТД в языке Си используются структуры. Но использование данных структурного типа значительно ограничено по сравнению с использованием базовых типов данных. Например, структурные данные нельзя использовать в различных арифметических и логических операциях. Для манипуляции с подобными данными надо писать набор функций, выполняющих различные действия, и вместо операций вызывать эти функции.
Кроме того, элементы структуры никак не защищены от случайной модификации. То есть любая функция (даже не из набора средств манипуляции структурными данными) может обратиться к элементу структуры. Это противоречит одному из основных принципов объектно-ориентированного программирования — инкапсуляции данных: никакие другие функции, кроме специальных функций манипуляции этим типом данных, не должны иметь доступ к элементам данных.
Рассмотрим реализацию понятия даты с использованием struct для того, чтобы определить представление даты date и множества функций для работы с переменными этого типа:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
struct date
{
int day; // день
int month; // месяц
int year; // год
};
void set_date(date* f, int d, int m, int y)
{
f->day = d;
f->month = m;
f->year = y;
}
void print_date(date* f)
{
printf("%d.%d.%d", f->day, f->month, f->year);
}
int main()
{
date today;
set_date(&today, 2, 4, 2014);
print_date(&today);
getchar();
return 0;
}
Никакой явной связи между функциями и типом данных в этом примере нет. Для вызова любой из описанных функций требуется в качестве аргумента передать указатель на экземпляр структуры.
Такую связь можно установить, описав функции как члены структуры. Эти функции могут действовать на данные, содержащиеся в самой структуре.
По умолчанию при объявлении структуры ее данные и функции являются общими, то есть у объектов типа структура нет ни инкапсуляции, ни защиты данных:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
struct date
{
int day; // день
int month; // месяц
int year; // год
void set_date(int d, int m, int y)
{
day = d; month = m; year = y;
}
void print_date(void);
};
void date::print_date(void)
{
printf("%d.%d.%d", day, month, year);
}
int main()
{
date today;
today.set_date(2, 4, 2014);
today.print_date();
getchar();
return 0;
}
Поля и методы
Функции, описанные в теле абстрактного типа данных, представляют собой методы или функции-члены и могут вызываться только для специальной переменной соответствующего типа с использованием стандартного синтаксиса для доступа к полям или данным-членам структуры.
Определение методов может осуществляться двумя способами:
- описание функции непосредственно при описании структуры;
- описание функции вне структуры.
Методы, которые определены внутри структуры, являются неявно встроенными (::
тело метода; }
- тип — тип возвращаемого значения метода
- АТД — имя абстрактного типа данных (имя структуры или класса)
- имя — имя метода
void date::print_date(void)
{ printf("%d.%d.%d",day, month, year);}
В методе имена параметров могут использоваться без явной ссылки на объект. В этом случае имя параметра относится к полю того объекта, для которого функция была вызвана.
Методы одной и той же структуры могут быть полиморфными, то есть перегруженными.
Права доступа
Концепция структуры в языке С++ (в отличие от Си) позволяет членам структуры быть общими, частными или защищенными:
- public – общие;
- private – частные;
- protected – защищенные.
Использование ключевого слова protected связано с понятием наследования.
Использование ключевого слова private ограничивает доступ к полям и методам, которые следуют за этой конструкцией. Поля private могут использоваться только методами самого АТД, а также несколькими привилегированными функциями, имеющими доступ к этим полям (в языке C++ это дружественные функции).
Ключевое слово public формирует интерфейс к объекту АТД.
Стандартным является размещение полей в частной области (private), а части методов – в общей части (public) абстрактного типа данных. В этом случае закрытая (private) часть определяет данные объекта и служебные функции, а методы общей части реализуют интерфейс работы с объектом.
Изменим структуру date так, чтобы скрыть представление данных (инкапсуляция данных):
2
3
4
5
6
7
8
{
private:
int month, day, year;
public:
void set(int, int, int);
void print();
};