Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР20-С++-16-сентября-2012 (1).doc
Скачиваний:
33
Добавлен:
12.11.2019
Размер:
1.18 Mб
Скачать

1.11. Инкапсуляция

Инкапсуляция – это принцип ООП, объединяющий в одном классе данные и методы, манипулирующие этими данными и защищающие данные класса от внешнего воздействия.

Обратимся к примеру из жизни, чтобы понять смысл этого принципа. Представьте себе, что в вашу квартиру пришел знакомый и переставил вашу мебель по своему усмотрению, не считаясь с вашим вкусом. Скорее всего, вам это не понравится, и вы перестанете приглашать этого человека в свой дом. Если же вы для перестановки мебели позовете помощников, то сначала объясните им, что и как надо переставить, тогда в результат их работы вы получите квартиру, обустроенную так, как это нужно вам.

Класс также защищает свое состояние (значения свойств) от несанкционированного изменения, это реализуется с помощью раздела класса private. Включенные в private свойства доступны только этому объекту, поэтому не могут быть изменены другими объектами. Для доступа к свойствам в раздел класса public включаются методы. Методы проверяют, возможно ли такое изменение состояния объекта под влиянием других объектов, и только после этого изменяют значения переменных состояния. Если переход в новое состояние невозможен, методы оставляют объект в прежнем состоянии.

Пример 20.18.

Изменим пример 20.7 с принтером. Предположим, во время профилактики вычислительной системы у принтера было отключено электропитание. Естественно, в этом случае наши попытки что-то напечатать ни к чему не приведут. Учтем это в нашей модели принтера. Добавим свойство is_on, отражающее подключение к принтеру электрического питания (0 – включено, 1 – выключено). Тогда состояние принтера определяется комбинацией значений двух свойств – is_on и status (табл. 20.2).

Таблица 20.2

Допустимые состояния принтера

is_on

status

Сообщение на экране

0

0

Принтер включен

1

0

Принтер включен Состояние: готов к работе

1

1

Принтер включен Состояние: печатает

При этом класс представляется в виде:

class Printer

{

char model[15];

int year;

int status;

int is_on; //Принтер включен (0 – нет,1 – да)

public:

Printer(char* _model, int _year);

void on_off(); //Включение/выключение питания

void set_print();

void stop_print();

void show();

};

//Конструктор

Printer :: Printer(char* _model, int _year)

{

strcpy(model, _model);

year=_year;

status=0;

is_on=0; //Принтер отключен по умолчанию

}

void Printer :: on_off()

{

//Метод моделирует нажатие кнопки включения

//питания:если оно выключено, то произойдет

//включение, и наоборот;

//одновременно при любых переключениях питания //принтер оказывается в состоянии готовности

//и печать не ведет

is_on=!is_on;

status=0;

}

 

void Printer :: set_print()

{

If (is_on) status=1; //Принтер будет печатать,

//если он включен

}

 

void Printer :: stop_print()

{

If (status) status=0; //Принтер остановится,

//если он до того печатал

}

 

void Printer :: show()

{

cout << "Модель: " << model << "Год выпуска: " << year << endl;

if (is_on)

{

cout << "Принтер включен";

if (status) cout << "Состояние: печатает";

else cout << "Состояние: готов к работе";

}

else cout << "Принтер выключен";

cout << endl;

}

Полный текст программы для примера 20.18:

//Пример 20.18

#include <iostream.h>

#include <conio.h>

class Printer

{

private:

char* model;//указатель на строку, которая будет

//содержать название модели принтера

//и разместится в динамической памяти

int year; //год выпуска

int status; //состояние принтера

int is_on; //Принтер включен (0 - нет,1 - да)

public:

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

Printer(char* _model, int _year);

//Деструктор

~Printer();

void init_printer(char* _model, int _year,int _is_on);

void on_off(); //Включение/выключение питания

void set_print();

void stop_print();

void show();

};

void Printer::init_printer(char* _model,int _year,int _is_on)

{

strcpy(model,_model); //инициализация свойства model

year=_year; //инициализация свойства year

is_on=_is_on;

status=0; //начальное состояние - готов к печати

}

void Printer :: on_off()

{

//Метод моделирует нажатие кнопки включения

//питания:если оно выключено, то произойдет

//включение, и наоборот;

//одновременно при любых переключениях питания

//принтер оказывает-ся в состоянии готовности

//и печать не ведет

is_on=!is_on;

status=0;

}

void Printer :: set_print()

{

if (is_on) status=1; //Принтер будет печатать,

//если он включен

}

void Printer :: stop_print()

{

if (status) status=0; //Принтер остановится,

//если он до того печатал

}

void Printer :: show()

{

cout << "Модель: " << model << " Год выпуска: " << year << endl;

if (is_on)

{

cout << "Принтер включен";

if (status) cout << "Состояние: печатает";

else cout << "Состояние: готов к работе";

}

else cout << "Принтер выключен";

cout << endl;

}

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

Printer :: Printer(char* _model, int _year)

{

int len=strlen(_model); //Определение длины

//строки

//Выделение памяти в динамической области

//для размещения строки и символа '\0'

model=new char[len+1];

strcpy(model, _model);

year=_year;

status=0;

is_on=0; //Принтер отключен по умолчанию

}

//Деструктор

Printer :: ~Printer()

{

//Освобождение динамической памяти

delete[] model;

//Присваивание указателю значения пустого

//указателя, обязательно в Visual C++

model = NULL;

}

int main()

{

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

Printer printer1("HP5P",2004);

printer1.show();

//Создание второго объекта

Printer printer2("Canon_BJC250",2000);

printer2.show();

cout << "\nНажмите любую клавишу..." ;

getch();

return 0;

}

Тестирование:

Класс запрещает прямой доступ к своим переменным состояния, поэтому не удастся реализовать недопустимое состояние is_on=0, status=1. Методы set_print(), stop_print(), on_off(), предоставляющие доступ к свойствам объекта, реализованы так, что также исключают это состояние объекта. В этом и заключается смысл понятия инкапсуляции.

Полный текст модифицированной программы для примера 20.18:

//Пример 20.18m

#include <iostream.h>

#include <conio.h>

class Printer

{

private:

char* model;//указатель на строку, которая будет

//содержать название модели принтера

//и разместится в динамической памяти

int year; //год выпуска

int status; //состояние принтера

int is_on; //Принтер включен (0 - нет,1 - да)

public:

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

Printer(char* _model, int _year,int _is_on);

//Деструктор

~Printer();

void init_printer(char* _model, int _year,int _is_on);

void on_off(); //Включение/выключение питания

void set_print();

void stop_print();

void show();

};

void Printer::init_printer(char* _model,int _year,int _is_on)

{

strcpy(model,_model); //инициализация свойства model

year=_year; //инициализация свойства year

is_on=_is_on;

status=0; //начальное состояние - готов к печати

}

void Printer :: on_off()

{

//Метод моделирует нажатие кнопки включения

//питания:если оно выключено, то произойдет

//включение, и наоборот;

//одновременно при любых переключениях питания

//принтер оказывает-ся в состоянии готовности

//и печать не ведет

is_on=!is_on;

status=0;

}

void Printer :: set_print()

{

if (is_on) status=1; //Принтер будет печатать,

//если он включен

}

void Printer :: stop_print()

{

if (status) status=0; //Принтер остановится,

//если он до того печатал

}

void Printer :: show()

{

cout << "Модель: " << model << " Год выпуска: " << year << endl;

if (is_on)

{

cout << " Принтер включен";

if (status) cout << " Состояние: печатает";

else cout << " Состояние: готов к работе";

}

else cout << " Принтер выключен";

cout << endl;

}

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

Printer :: Printer(char* _model, int _year,int _is_on)

{

int len=strlen(_model); //Определение длины

//строки

//Выделение памяти в динамической области

//для размещения строки и символа '\0'

model=new char[len+1];

strcpy(model, _model);

year=_year;

status=0;

is_on=_is_on; //Принтер отключен по умолчанию

}

//Деструктор

Printer :: ~Printer()

{

//Освобождение динамической памяти

delete[] model;

//Присваивание указателю значения пустого

//указателя, обязательно в Visual C++

model = NULL;

}

int main()

{

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

Printer printer1("HP5P",2004,0);

printer1.show();

//Создание второго объекта

Printer printer2("Canon_BJC250",2000,1);

printer2.show();

cout << "\nНажмите любую клавишу..." ;

getch();

return 0;

}

Тестирование: