билеты. OOП билеты 12 шт. 1. Принципы опп наследование, инкапсуляция, полиморфизм Наследование
Скачать 225.77 Kb.
|
date() { delete[] month; } // деструктор . Так, для класса X деструктор будет иметь имя |
using namespace std;
int main() {
int a = 0, b =10;
cout << b/a << endl;cin.get();
return 0;
}
При попытке запустить программу на выполнение видим следующее:
Для обработки исключительной ситуации необходимо операцию деления поместить в блок защищенного кода:
#include
using namespace std;
int main() {
int a = 0, b = 10;
try {
cout << b / a << endl;
}
catch (…)
{
cout << «error»;
}
cin.get();
return 0;
}
Для корректного запуска программы необходимо также произвести настройки среды разработки и разрешить обработку структурных исключений. Для этого переходим к меню Имя проекта->Свойства
И для пункта меню C/C++ ->Code Generation->Enable C++ Exceptions устанавливаем значение Yes With SEH Exceptions (/EHa).
При запуске программы на выполнение имеем следующий результат:
При компиляции с параметром /EHa, в число обрабатываемых исключений могут входить структурированные исключения C и создаваемые системой или приложением асинхронные исключения, например нарушения, связанные с защитой памяти, делением на ноль и числами с плавающей запятой.
3. Классы (определение, описание, спецификаторы, элементы)
Синтаксис:
class имя класса {
элементы класса
};
или
struct имя класса {
элементы класса
};
С помощью спецификаторов доступа можно управлять видимостью элементов класса. Спецификатор private (закрытый) означает видимость элементов только для методов и друзей класса. Спецификатор protected (защищенный) означает видимость элементов только для методов и друзей класса и его наследников (наследники могут видеть эти элементы только в объектах собственного типа). Спецификатор public (открытый) означает видимость элементов из любого кода. Действие любого спецификатора распространяется до следующего спецификатора или до конца объявления класса. По умолчанию для элементов класса, объявленного с помощью struct, установлен доступ public, а для класса, объявленного с помощью class, – private.
Рекомендуется все поля в class делать закрытыми или защищенными элементами, а в struct – открытыми.
4. Данные и свойства класса
Данные-члены — это те члены, которые содержат данные класса — поля, константы, события. Данные-члены могут быть статическими (static). Член класса является членом экземпляра, если только он не объявлен явно как static. Давайте рассмотрим виды этих данных:
Свойства (property)
Это наборы функций, которые могут быть доступны клиенту таким же способом, как общедоступные поля класса. В C# предусмотрен специальный синтаксис для реализации чтения и записи свойств для классов, поэтому писать собственные методы с именами, начинающимися на Set и Get, не понадобится. Поскольку не существует какого-то отдельного синтаксиса для свойств, который отличал бы их от нормальных функций, создается иллюзия объектов как реальных сущностей, предоставляемых клиентскому коду.
5. Конструкторы, деструкторы, параметры this
Конструктор — функция, предназначенная для инициализации объектов класса.Рассмотрим класс date:
class date
{
int day, month, year;
public:
set(int, int, int);
};
Нигде не утверждается, что объект должен быть инициализирован, и программист может забыть инициализировать его или сделать это дважды.
ООП дает возможность программисту описать функцию, явно предназначенную для инициализации объектов. Поскольку такая функция конструирует значения данного типа, она называется конструктором. Конструктор всегда имеет то же имя, что и сам класс и никогда не имеет возвращаемого значения. Когда класс имеет конструктор, все объекты этого класса будут проинициализированы.
class date {
int day, month, year;
public:
date(int, int, int); // конструктор
};
Если конструктор требует аргументы, их следует указать:
date today = date(6,4,2014); // полная форма
date xmas(25,12,0); // сокращенная форма
// date my_burthday; // недопустимо, опущена инициализация
Если необходимо обеспечить несколько способов инициализации объектов класса, задается несколько конструкторов:
class date {
int month, day, year;
public:
date(int, int, int); // день месяц год
date(char*); // дата в строковом представлении
date(); // дата по умолчанию: сегодня
};
Деструкторы
Определяемый пользователем класс имеет конструктор, который обеспечивает надлежащую инициализацию. Для многих типов также требуется обратное действие. Деструктор обеспечивает соответствующую очистку объектов указанного типа. Имя деструктора представляет собой имя класса с предшествующим ему знаком «тильда»
Функция- член класса | Дружественная функция |
class А { ... public: A operator !(); ... }; | class A { ... public: friend A operator !(A); ... }; |
10. Перезагрузка бинарных операций класса
Если бинарная операция перегружается с использованием метода класса, то в качестве своего первого аргумента она получает неявно переданную переменную класса (указатель this на объект), а в качестве второго — аргумент из списка параметров. То есть, фактически бинарная операция, перегружаемая методом класса, имеет один аргумент (правый операнд), а левый передается неявно через указатель this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class complex
{
double real;
double imag;
public:
complex operator +(const complex &);
...
};
complex complex :: operator +(complex &c) {
complex temp;
temp.real = this->real + c.real;
temp.imag = this->imag + c.imag;
return(temp);
}
Если бинарная операция перегружается дружественной функцией, то в списке параметров она должна иметь оба аргумента:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include
using namespace std;
class complex
{
double real;
double imag;
public:
complex(double r = 0, double i = 0)
{
real = r; imag = i;
}
void out(void)
{
cout << real << " + " << imag << "i" << endl;
}
friend complex operator + (const complex &c1, const complex &c2);
};
complex operator + (const complex &c1, const complex &c2)
{
complex temp;
temp.real = c1.real + c2.real;
temp.imag = c1.imag + c2.imag;
return(temp);
}
int main()
{
complex a(3.1, 4.5), b(2.3, 6.7); // инициализация
complex c;
c = a + b;
c.out();
cin.get();
return 0;
}
Результат выполнения
Для каждой комбинации типов операндов в переопределяемой операции необходимо ввести отдельную функцию, т.е. компилятор не может производить перестановку операндов местами, даже если базовая операция допускает это. Например, если необходима операция сложения комплексного и вещественного чисел:
complex a, c, d;
double b;
c = a + b;
d = b + a;
то необходимо переопределить операцию сложения дважды:
1
2
friend complex operator + (complex, double);
friend complex operator + (double, complex);
11. Перезагрузка операции преобразования типа
Например, преобразуем значение типа int в значение типа double:
1 2 | int a = 7; double b = a; // значение типа int неявно конвертируется в значение типа double |
Язык C++ по умолчанию знает, как выполнять преобразования встроенных типов данных. Однако он не знает, как выполнять конвертацию с пользовательскими типами данных (например, с классами). Именно здесь вступает в игру перегрузка операций преобразования типов данных. Рассмотрим следующий класс:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Dollars { private: int m_dollars; public: Dollars(int dollars=0) { m_dollars = dollars; } int getDollars() { return m_dollars; } void setDollars(int dollars) { m_dollars = dollars; } }; |
Класс Dollars содержит некое количество долларов в виде целого числа (переменная-член m_dollars) и предоставляет функции доступа для получения и установления значения m_dollars. В нем также есть конструктор для конвертации значений типа int в тип Dollars (при создании объекта пользователь передает в качестве аргумента значение типа int, которое затем преобразуется в значение типа Dollars).
Если мы можем конвертировать int в Dollars, то логично было бы, если бы мы могли конвертировать и Dollars обратно в int, не так ли? Иногда это может быть полезным.
В следующем примере мы используем метод getDollars() для конвертации значения типа Dollars в тип int для его последующего вывода через функцию printInt():
1 2 3 4 5 6 7 8 9 10 11 12 | void printInt(int value) { std::cout << value; } int main() { Dollars dollars(9); printInt(dollars.getDollars()); // выведется 9 return 0; } |
Согласитесь, вызывать каждый раз метод getDollars() не очень удобно. Было бы проще перегрузить операцию преобразования значений типа Dollars в тип int. Делается это следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Dollars { private: int m_dollars; public: Dollars(int dollars=0) { m_dollars = dollars; } // Перегрузка операции преобразования значений типа Dollars в значения типа int operator int() { return m_dollars; } int getDollars() { return m_dollars; } void setDollars(int dollars) { m_dollars = dollars; } }; |
12. Наследование
Наследование в C++ происходит между классами и имеет тип отношений «является». Класс, от которого наследуют, называется родительским (или «базовым», «суперклассом»), а класс, который наследует, называется дочерним (или «производным», «подклассом»).
В диаграмме, представленной выше, Фрукт является родительским классом, а Яблоко и Банан — дочерними классами.
В этой диаграмме Треугольник является дочерним классом (родитель — Фигура) и родительским (для Правильного треугольника) одновременно.
Дочерний класс наследует как поведение (методы), так и свойства (переменные-члены) от родителя (с учетом некоторых ограничений доступа, которые мы рассмотрим чуть позже). Эти методы и переменные становятся членами дочернего класса.
Поскольку дочерние классы являются полноценными классами, то они могут (конечно) иметь и свои собственные члены.