ООП в С/С++

Классы в C++

Поскольку C++ – объектно-ориентированный язык, он позволяет использовать при разработке программ как готовые классы, доступные через соответствующие библиотеки, так и классы, разработанные пользователем.

Рассмотрим создание класса пользователем и применение класса, созданного пользователем, в программе.

Объявление класса:

class <имя класса>

{

public:
<объявление переменных, констант, функций>
private:
<объявление переменных, констант, функций>
protected:
<объявление переменных, констант, функций>
};

Объявление класса начинается с ключевого слова class. Переменные, константы, функции, включенные в класс, называются членами класса. Члены класса объявляются в одном из трех разделов класса: public, private, protected. Включение члена класса в тот или иной раздел влияет на доступность этого члена для объектов других классов.

Раздел public обеспечивает доступность помещенных в него свойств и методов для любых объектов. Это внешняя часть класса, или интерфейс его взаимодействия с другими классами.

Раздел private обеспечивает сокрытие помещенных в него свойств и методов от других объектов, делая их недоступными объектам других классов. Таким образом, класс защищает свои данные (свое состояние) от внешнего воздействия. Посторонний объект может воздействовать на объект данного класса только через интерфейс этого класса.

Раздел protected позволяет, используя механизм наследования, передавать включенные в него члены класса по наследству.

Рассмотрим в качестве примера класс принтеров. Включим в его состав следующие свойства: модель, год выпуска и состояние принтера; спрячем эти свойства от постороннего воздействия, поместив в раздел private. Ограничимся двумя возможными состояниями принтера: 0 – принтер готов к работе, 1 – принтер печатает. Методы сделаем доступными для других объектов. Метод init_printer() позволит установить начальные значения свойствам принтера. Метод set_print() переведет принтер в состояние печати, если принтер до того находился в состоянии готовности, и не изменит его состояния, если принтер уже печатал. Метод stop_print() приводит к остановке печати. Метод show() отображает состояние принтера на экране:

class Printer
{

private:
char model[15]; //модель принтера
int year; //год выпуска
int status; //состояние принтера

public:
void init_printer(char* _model, int _year);
void set_print();
void stop_print();
void show();
};

//Замечание. Если раздел private включен в объявлении класса первым, ключевое слово private //можно опустить:

class Printer
{
char model[15]; //модель принтера
int year; //год выпуска <>brint status; //состояние принтера
public:
void init_printer(char*_model,int_year);
void set_print();
void stop_print();
void show();
};

//Описание методов:

void Printer::init_printer(char* _model,int _year)
{
strcpy(model,_model); //инициализация свойства model
year=_year; //инициализация свойства year
status=0; //начальное состояние – готов к печати
}
void Printer :: set_print()
{
if (!status) status=1;
}

void Printer :: stop_print()
{
status = 0;
}
void Printer :: show()
{
cout<<"Model:"<}

В главную часть программы – функцию main() – включим следующие действия: создание объекта, инициализация свойств объекта, изменение состояния объекта и вывод его текущего состояния на экран:

int main(void)
{
Printer printer; //создание объекта

//инициализация свойств объекта

printer.init_printer("HP5P", 1999);
printer.show(); //вызов метода объекта
printer.set_print();
printer.show();
printer.set_print();
printer.show();
printer.stop_print();
printer.show();
return 0;
}

В результате работы программы на экране появятся 4 строки текста:

Model: HP5P year: 1999 status: 0,

Model: HP5P year: 1999 status: 1,

Model: HP5P year: 1999 status: 1,

Model: HP5P year: 1999 status: 0.

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

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

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

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

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

Допустимые состояния принтера
is_on 0 1 1
status 0 0 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;
}

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

Полиморфизм – это принцип ООП, позволяющий включать в состав класса несколько функций с одинаковыми именами, но выполняющих различные действия. Такие функции должны иметь различные списки параметров, они должны отличаться или количеством параметров в списках, или типами соответствующих параметров. Полиморфизм в ООП есть проявление свойства языка C++, называемого перегрузкой функций (п. 16.4).

Пример полиморфизма – класс графических примитивов Draw. Класс может проявить себя как текст, прямоугольник или окружность. Для этого в класс включены три метода show(), различающиеся параметрами.

Компилятор, обрабатывая вызов функции, сопоставляет список фактических параметров со списками формальных параметров всех методов класса, имеющих то же имя, и выбирает ту функцию, у которой список формальных параметров совпал со списком фактических параметров при вызове функции:

#include

#include

class Draw
{
int x1, y1, x2, y2, r;
char *message;
public:
Draw();
virtual ~Draw();
void show();
void show(int xx1, int yy1, int xx2, int yy2);
void show(int xx1, int xx2, int rr);
};

Draw::Draw()
{
x1=x2=y2=y1=r=0;
message=new char[10];
strcpy(message, "text");
}

Draw::~Draw()
{
delete[] message;
message=NULL;
}
void Draw::show()
{
cout << message << endl;
}
void Draw::show(int xx1,int yy1,int xx2,int yy2)
{
cout << "Rectangle" << endl;
}

void Draw::show(int xx1,int xx2,int rr)
{
cout << "Circle" << endl;
}
int main(void)
{
Draw draw;
draw.show();
draw.show(1,1,20,10);
draw.show(10,10,10);
return 0;
}

В результате выполнения программы на экране появляются сообщения:

Text

Rectangle

Circle

Наследование

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

Созданные с использованием механизма наследования новые классы называются классами-наследниками или классами-потомками.

//Объявление базового класса

class A
{

… //Члены класса A
};

//Объявление класса-наследника
class B : public A
{

… //Собственные члены класса B
};

Новые классы наследуют только те свойства и методы, которые объявлены в разделах public и protected базовых классов. При этом свойства и методы из раздела protected доступны только базовому классу и его наследникам, тогда как свойства и методы из раздела public доступны объектам любого класса (рис. 17.1). Исключением из этого правила являются конструкторы и деструкторы, которые не наследуются.

Рис. Уровни доступа к членам класса

В состав класса B входят собственные члены и члены класса A из разделов public и protected.

Рассмотрим пример наследования, в качестве базового класса возьмем класс person, характеризующий любого человека, и включим в раздел protected свойство класса name – имя человека:

class person
{
protected:
char name[20];
}; //Создадим на основе класса person класс-наследник student:

class student : public person
{
char department[20]; // факультет
public:
student(char* _name, char* _department);
void message();
};
//Конструктор
student :: student(char* _name, char* _department)
{
strcpy(name, _name);
strcpy(department, _department);
}
//message – метод, сообщающий сведения об объекте
void student::message()
{
cout << "My name is " << name << ". I study at " << department << endl;
} //Как видно, методы класса student используют как собственное свойство, так и свойство, полученное по наследству. //Создание объекта класса student и вызов его метода ничем не отличаются от того, как это делается для класса без наследования:

int main(void)
{
student N("Nick", "SS,SK,VT");
N.message();
return 0;
}

Во время выполнения такой программы на экране появляется сообщение:

My name is Nick. I study at SS, SK, VT.

Теперь рассмотрим наследование методов базового класса, включим в базовый класс конструктор, инициализирующий собственное свойство базового класса значением "Noname", и метод message, сообщающий информацию о классе:

class person
{
protected:
char name[20];
public:
person();
void message();
};
person :: person()
{
strcpy(name, "Noname");
}
void person::message()
{
cout << "My name is " << name << endl;
}

Таким образом, в класс-наследник student теперь включены два метода message, имеющие одинаковый тип и одинаковый список параметров – один из базового класса, другой – собственный. Собственный метод доступен через имя объекта. Однако можно получить доступ к унаследованному методу, если использовать для доступа к методу указатель соответствующего типа – указатель на базовый класс:

int main(void)
{
person A;
student B("Ann", "SS,SK,VT");

A.message();
B.message();
person* pperson = &B;
pperson->message();
student* pstudent = &B;
pstudent->message();
return 0;
}

На экране увидим сообщения:

Noname Сообщение об= объекте A

Ann SS,SK,VT Сообщение об объекте B (используется собственный метод message)

Ann Сообщение об объекте B (используется метод message, полученный по наследству)

Ann SS,SK,VT Сообщение об объекте B (используется собственный метод message)

В С++ можно избежать получения по наследству метода, если метод с таким же именем включен в класс-потомок, для этого используется механизм виртуальных функций.

Виртуальная функция - это функция, объявленная в базовом классе с помощью ключевого слова virtual, такая функция в классах-потомках замещается на функцию, принадлежащую производному классу и имеющую то же имя:

class person
{
protected:
char name[20];
public:
person();
virtual void message();
};

Теперь результатом выполнения программы будут следующие сообщения:

Noname Сообщение об объекте A

Ann SS,SK,VT Сообщение об объекте B (используется собственный метод message)

Ann SS,SK,VT Сообщение об объекте B (используется собственный метод message)

Ann SS,SK,VT Сообщение об объекте B (используется собственный метод message)

С помощью виртуальных функций можно создать класс-наследник, имеющий тот же интерфейс, что и базовый класс, но обладающий своей собственной моделью поведения. Механизм виртуальных функций реализуется следующим образом: обычно обработка вызовов функций выполняется на этапе компиляции и завершается на этапе редактирования связей, когда вызов метода жестко связывается с соответствующей функцией (раннее связывание); если метод объявлен как виртуальный, выполняется так называемое позднее связывание, т. е. связывание вызова и функции во время выполнения программы. <Подробней можете узнать на сайте: >

Подробней можете узнать на сайте:http://itedu.ru

Материал взят с сайта: dvo.sut.ru