Курс «ООП»

![Описание класса class <имя>{ [ private: ] <описание скрытых элементов> Описание класса class <имя>{ [ private: ] <описание скрытых элементов>](https://present5.com/presentation/3/189889999_169801055.pdf-img/189889999_169801055.pdf-2.jpg)

























Курс «ООП» "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. " Rich Cook Использованы материалы из книги Павловской Т. А. ©Павловская Т. А. Язык С++
Описание класса class <имя>{ [ private: ] <описание скрытых элементов> public: <описание доступных элементов> }; Поля класса: l могут иметь любой тип, кроме типа этого же класса (но могут быть указателями или ссылками на этот класс); l могут быть описаны с модификатором const; l могут быть описаны с модификатором static, но не как auto, extern и register. Инициализация полей при описании не допускается. Классы могут быть глобальными и локальными. 2
Конструкторы ¨ Конструктор не возвращает значение, даже типа void. Нельзя получить указатель на конструктор. ¨ Класс может иметь несколько конструкторов с разными параметрами для разных видов инициализации (при этом используется механизм перегрузки). ¨ Конструктор, вызываемый без параметров, называется конструктором по умолчанию. ¨ Параметры конструктора могут иметь любой тип, кроме этого же класса. Можно задавать значения параметров по умолчанию. Их может содержать только один из конструкторов. ©Павловская Т. А. Язык С#
Конструкторы - продолжение ¨ Если программист не указал ни одного конструктора, компилятор создает его автоматически. Такой конструктор вызывает конструкторы по умолчанию для полей класса и конструкторы по умолчанию базовых классов. ¨ Конструкторы не наследуются. ¨ Конструкторы нельзя описывать как const, virtual и static. ¨ Конструкторы глобальных объектов вызываются до вызова функции main. ¨ Локальные объекты создаются, как только становится активной область их действия. ¨ Конструктор запускается и при создании временного объекта (например, при передаче объекта из функции). ©Павловская Т. А. Язык С#
Вызов конструктора выполняется, если в программе встретилась одна из конструкций: имя_класса имя_объекта [(список параметров)]; имя_класса (список параметров); имя_класса имя_объекта = выражение; monstr Super(200, 300), Vasia(50), Z; monstr X = monstr(1000); monstr Y = 500; ©Павловская Т. А. Язык С#
Несколько конструкторов enum color {red, green, blue}; class monstr{ int health, ammo; color skin; char *name; public: monstr(int he = 100, int am = 10); monstr(color sk); monstr(char * nam); int get_health(){return health; } int get_ammo(){return ammo; } }; ©Павловская Т. А. Язык С#
Реализация конструкторов monstr: : monstr(int he, int am) {health = he; ammo = am; skin = red; name = 0; } monstr: : monstr(color sk){ switch (sk){ case red : health = 100; ammo = 10; skin = red; name = 0; break; case green: health = 100; ammo = 20; skin = green; name = 0; break; case blue : health = 100; ammo = 40; skin = blue; name = 0; break; } } monstr: : monstr(char * nam){ name = new char [strlen(nam) + 1]; strcpy(name, nam); health = 100; ammo = 10; skin = red; } ©Павловская Т. А. Язык С#
Список инициализаторов конструктора monstr: : monstr(int he, int am): health (he), ammo (am), skin (red), name (0){ } Конструктор копирования T: : T(const T&) { /* Тело конструктора */ } l при описании нового объекта с инициализацией другим объектом; l при передаче объекта в функцию по значению; l при возврате объекта из функции. l при обработке исключений. ©Павловская Т. А. Язык С#
Пример конструктора копирования monstr: : monstr(const monstr &M){ if (M. name){ name = new char [strlen(M. name) + 1]; strcpy(name, M. name); } else name = 0; health = M. health; ammo = M. ammo; skin = M. skin; } monstr Vasia (blue); monstr Super = Vasia; monstr *m = new monstr ("Ork"); monstr Green = *m; ©Павловская Т. А. Язык С#
Статические поля l. Память под статическое поле выделяется один раз class A { public: static int count; /* Объявление */ }; int A: : count; // Определение // int A: : count = 10; Вариант определения l поля доступны через имя класса и через имя объекта: A *a, b; cout << A: : count << a->count << b. count; l На статические поля распространяется действие спецификаторов доступа, поэтому статические поля, описанные как private, можно изменить только с помощью статических методов. l Память, занимаемая статическим полем, не учитывается при определении размера объекта с помощью операции sizeof. ©Павловская Т. А. Язык С#
Статические методы class A{ static int count; public: static void inc_count(){ count++; } }; A: : int count; void f(){ A a; // a. count++ — нельзя a. inc_count(); // или A: : inc_count(); ©Павловская Т. А. Язык С#
Дружественные функции и классы ¨ Дружественная функция объявляется внутри класса, к элементам которого ей нужен доступ, с ключевым словом friend. ¨ Дружественная функция может быть обычной функцией или методом другого ранее определенного класса. ¨ Одна функция может быть дружественной сразу нескольким классами. ©Павловская Т. А. Язык С#
Дружественные функции - пример class monstr; class hero{ public: void kill(monstr &); }; class monstr{ friend int steal_ammo(monstr &); friend void hero: : kill(monstr &); }; int steal_ammo(monstr &M){return --M. ammo; } void hero: : kill(monstr &M){ M. health = 0; M. ammo = 0; } ©Павловская Т. А. Язык С#
Дружественные классы - пример class hero{ . . . friend class mistress; } class mistress{ . . . void f 1(); void f 2(); } ©Павловская Т. А. Язык С#
Деструкторы Деструктор вызывается автоматически , когда объект выходит из области видимости: l для локальных объектов — при выходе из блока, в котором они объявлены; l для глобальных — как часть процедуры выхода из main; l для объектов, заданных через указатели , деструктор вызывается неявно при использовании операции delete. Пример деструктора: monstr: : ~monstr() {delete [] name; } ©Павловская Т. А. Язык С#
Деструктор можно вызвать явным образом путем указания полностью уточненного имени, например: monstr *m; . . . m -> ~monstr(); Деструктор: l не имеет аргументов и возвращаемого значения; l не может быть объявлен как const или static; l не наследуется; l может быть виртуальным l Если деструктор явным образом не определен, компилятор автоматически создает пустой деструктор. ©Павловская Т. А. Язык С#
Рекомендации по составу класса Как правило, класс как тип, определенный пользователем, должен содержать скрытые (private) поля и следующие функции: • конструкторы, определяющие, как инициализируются объекты класса; • набор методов, реализующих свойства класса (при этом методы, возвращающие значения скрытых полей класса, описываются с модификатором const, указывающим, что они не должны изменять значения полей); • набор операций, позволяющих копировать, присваивать, сравнивать объекты и производить с ними другие действия, требующиеся по сути класса; • класс исключений, используемый для сообщений об ошибках с помощью генерации исключительных ситуаций ©Павловская Т. А. Язык С#
Наследование. Простое наследование классов. ©Павловская Т. А. Язык С++
Наследование является мощнейшим инструментом ООП и применяется для следующих взаимосвязанных целей: n исключения из программы повторяющихся фрагментов кода; n упрощения модификации программы; n упрощения создания новых программ на основе существующих. n Кроме того, наследование является единственной возможностью использовать объекты, исходный код которых недоступен, но в которые требуется внести изменения. ©Павловская Т. А. (СПб. ГУ ИТМО)
Синтаксис наследования Ключи доступа class имя : [private | protected | public] базовый_класс { тело класса }; class A {. . . }; class B {. . . }; class C {. . . }; class D: A, protected B, public C {. . . }; ©Павловская Т. А. (СПб. ГУ ИТМО)
n В наследнике можно описывать новые поля и методы и переопределять существующие методы. Переопределять методы можно несколькими способами. n Если какой-либо метод в потомке должен работать совершенно по-другому, чем в предке, метод описывается в потомке заново. При этом он может иметь другой набор аргументов. n Если требуется внести добавления в метод предка, то в соответствующем методе потомка наряду с описанием дополнительных действий выполняется вызов метода предка с помощью операции доступа к области видимости. n Если в программе планируется работать одновременно с различными типами объектов иерархии или планируется добавление в иерархию новых объектов, метод объявляется как виртуальный с помощью ключевого слова virtual. Все виртуальные методы иерархии с одним и тем же именем должны иметь одинаковый список аргументов. ©Павловская Т. А. (СПб. ГУ ИТМО)
Правила наследования Ключ доступа Спецификатор в Доступ в производном базовом классе private private нет protected private public private protected private нет protected public protected public private нет protected public ©Павловская Т. А. (СПб. ГУ ИТМО)
Иными словами: • private элементы базового класса в производном классе недоступны вне зависимости от ключа. Обращение к ним может осуществляться только через методы базового класса. • Элементы protected при наследовании с ключом private становятся в производном классе private, в остальных случаях права доступа к ним не изменяются. • Доступ к элементам public при наследовании становится соответствующим ключу доступа. ©Павловская Т. А. (СПб. ГУ ИТМО)
Если базовый класс наследуется с ключом private, можно выборочно сделать некоторые его элементы доступными в производном классе: class Base{ . . . public: void f(); }; class Derived : private Base{ . . . public: Base: : void f(); }; ©Павловская Т. А. (СПб. ГУ ИТМО)
Простое наследование class daemon : public monstr{ int brain; public: // ------- Конструкторы: daemon(int br = 10){brain = br; }; daemon(color sk) : monstr (sk) {brain = 10; } daemon(char * nam) : monstr (nam) {brain = 10; } daemon(daemon &M) : monstr (M) {brain = M. brain; } Если конструктор базового класса требует указания параметров, он должен быть явным образом вызван в конструкторе производного класса в списке инициализации ©Павловская Т. А. (СПб. ГУ ИТМО)
Порядок вызова конструкторов Конструкторы не наследуются , поэтому производный класс должен иметь собственные конструкторы. Порядок вызова конструкторов: l. Если в конструкторе потомка явный вызов конструктора предка отсутствует, автоматически вызывается конст- руктор предка по умолчанию. l. Для иерархии, состоящей из нескольких уровней, конструкторы предков вызываются начиная с самого верхнего уровня. После этого выполняются конструкторы тех элементов класса, которые являются объектами, в порядке их объявления в классе, а затем исполняется конструктор класса. l. В случае нескольких предков их конструкторы вызываются в порядке объявления. ©Павловская Т. А. (СПб. ГУ ИТМО)
Наследование деструкторов l. Деструкторы не наследуются. Если деструктор в производном классе не описан, он формируется автоматически и вызывает деструкторы всех базовых классов. l В деструкторе производного класса не требуется явно вызывать деструкторы базовых классов, это будет сделано автоматически. Для иерархии, состоящей из нескольких уровней, деструкторы вызываются в порядке, строго обратном вызову конструкторов: сначала вызывается деструктор класса, затем — деструкторы элементов класса, а потом деструктор базового класса. ©Павловская Т. А. (СПб. ГУ ИТМО)

