- •1. Комментарии
- •2. Константы
- •3. Встраиваемые функции Встраиваемые функции
- •4. Объявление структур, объединений и перечислений
- •5. Объявление переменных
- •5. Ссылки Что такое ссылка и что с ней можно делать
- •Ссылку можно рассматривать как еще одно имя объекта. В основном ссылки используются для задания параметров и возвращаемых функциями значений, а также для перегрузки операций.
- •6. Использование спецификатора void
- •7. Преобразование стандартных типов данных.
- •8. Новые операции new, delete, операция расширения области видимости
- •1. Операция new
- •2. Операция delete
- •3. Операция :: области видимости
- •9. Объявление функций. Аргументы по умолчанию
- •10. Перегрузка функций
- •Когда использовать перегрузку
- •Новые возможности по сравнению с Си
- •Объектно-ориентированные особенности языка
- •Две роли классов
- •Поля класса
- •Конструкторы класса
- •13. Перегрузка операций
- •Перегрузка операций
- •Перегрузка унарных операций
- •Перегрузка бинарных операций
- •Перегрузка операции присваивания
- •Перегрузка операции приведения типа
- •14. Дружественные функции
- •15. Сходства и различия классов, структур и объединений.
- •Отличия структур и объединений от классов
- •16. Классы и объекты. Определение класса и области видимости. Опережающее объявление класса
- •Две роли классов
- •Поля класса
- •17. Использование спецификатора класса памяти static. Статические компоненты класса
- •18. Константные объекты и константные методы
- •19. Неявный указатель this
- •20. Указатели на член класса
- •21. Локальные и вложенные классы
- •22. Специальный вид методов класса - конструкторы и деструкторы. Некоторые особенности конструкторов и деструкторов Конструкторы класса
- •23. Классы, содержащие объекты других классов
- •24. Создание объектов с различным временем жизни
- •25. Массивы объектов класса
- •26. Особенности копирования объектов Конструктор копирования
- •27. Заготовка класса без наследников
- •28. Пример вектора с неповерхностным копированием.
- •29. Излишнее копирование. Конструктор копии. Операции присваивания.
- •1. Излишнее копирование
- •2. Конструктор копирования
- •3. Операции присваивания
- •30. Преобразование типов. Стандартные преобразования. Явное преобразование типов
- •Преобразования указателей и ссылок
- •Явные преобразования типов
- •Неявное преобразование типа
- •31. Преобразования абстрактных типов данных (преобразование типов данных, созданных программистом)
- •32. Наследование классов
- •33. Доступ к наследуемым членам класса
- •34. Стандартные преобразования типов при наследовании
- •35. Инициализация объекта порожденного класса. Конструктор копии. Операция присваивания.
- •3. Операции присваивания
- •37. Виртуальные функции. Объявления виртуальных функций. Чисто виртуальные функции
- •Методы(функции)
- •38. Таблица виртуальных функций. Случаи, когда вызов виртуальной функции не будет виртуальным. Виртуальные деструкторы
- •39. Ввод-вывод файлов. Потоки ввода-вывода. Библиотека ввода-вывода (iostream). Группы классов библиотеки ввода вывода
- •40. Краткая характеристика иерархии классов производных от conbuf.
- •Класс conbuf (constrea.H)
- •Функции-элементы
- •41. Иерархия классов производных от ios
- •42. Состояния потока. Ошибки потоков. Состояние потока
- •С каждым потоком связан набор флагов, которые управляют форматированием потока. Они представляют собой битовые маски, которые определены в классе ios как данные перечисления. Манипуляторы
- •Шаблоны и наследование. Шаблоны и конфигурация компиляторов. Достоинства и недостатки шаблонов.
- •Совместное использование шаблонов и наследования
- •Достоинства и недостатки шаблонов
- •Исключения Применение try, catch, throw
- •47. Обработка исключительных ситуаций. Обработка завершения. Обработка структурных исключений, заявление исключения, фильтрующие выражение. Исключительные ситуации
- •Обработка исключительных ситуаций
- •Обработчик завершения
- •48. Стратегии взаимодействия объектов в программе. Программа как система взаимодействующих объектов. Система объектов, управляемых сообщениями
- •1. Программа, как система взаимодействия объектов.
- •49. Элементы объектно-ориентированного анализа и объектно-ориентированного проектирования. Диаграммы классов. Отношения классов: ассоциация, наследование, агрегация, использование.
- •51. Элементы объектно-ориентированного анализа и объектно-ориентированного проектирования. Диаграммы объектов, назначения, отношения между объектами. Диаграммы объектов (object diagrams)
Перегрузка операции присваивания
Операция присваивания определена в любом классе по умолчанию как поэлементное копирование. Эта операция вызывается каждый раз, когда одному существующему объекту присваивается значение другого. Если класс содержит поля ссылок на динамически выделяемую память, необходимо определить собственную операцию присваивания. Чтобы сохранить семантику операции, операция-функция должна возвращать ссылку на объект, для которого она вызвана, и принимать в качестве параметра единственный аргумент - ссылку на присваиваемый объект:
monster& operator = (const monster &M)
{
if (&M == this) return *this; // Проверка на самоприсваивание
if (name) delete [] name;
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;
return *this;
}
Операцию присваивания можно определять только в теле класса. Она не наследуется.
Перегрузка операции приведения типа
Можно определить функции-операции, которые будут осуществлять преобразование класса к другому типу. Формат:
operator имя_нового_типа ();
Тип возвращаемого значения и параметры указывать не требуется. Можно определять виртуальные функции преобразования типа.
Пример:
monster::operator int(){return health;}
...
monster Vasia; cout << int(Vasia);
Перегрузка new, delete. Операции создания и уничтожения объектов в динамической памяти могут быть переопределены следующим образом
void *operator new(size_t size);
void operator delete (void *);
где void * - указатель на область памяти, выделяемую под объект, size - размер объекта в байтах, size_t - тип размерности области памяти, int или long.
Переопределение этих операций позволяет написать собственное распределение памяти для объектов класса.
Операции, не допускающие перегрузки. В С++ существует несколько операций, не допускающих перегрузки:
. прямой выбор члена объекта класса;
.* обращение к члену через указатель на него;
?: условная операция;
:: операция указания области видимости;
sizeof операция вычисления размера в байтах;
# препроцессорная операция.
14. Дружественные функции
Иногда желательно дать функциям не членам возможность доступа к закрытой части класса. У класса есть механизм предоставления права доступа к своей закрытой части функциям не членам. Просто в описание класса помещается описание функции, перед которым стоит ключевое слово friend. Например, если имеется
class Vec; // Vec - имя класса
class vector {
friend Vec operator+(Vec, Vec);
//...
};
То вы можете написать
Vec operator+(Vec a, Vec b)
{
int s = a.size();
if (s != b.size()) error("плохой размер вектора для +");
Vec& sum = *new Vec(s);
int* sp = sum.v;
int* ap = a.v;
int* bp = b.v;
while (s--) *sp++ = *ap++ + *bp++;
return sum;
}
Одним из особенно полезных аспектов механизма friend является то, что функция может быть другом двух и более классов. Чтобы увидеть это, рассмотрим определение vector и matrix, а затем определение функции умножения.
Теперь, наконец, можно обсудить, в каких случаях для доступа к закрытой части определяемого пользователем типа использовать члены, а в каких - друзей. Некоторые операции должны быть членами: конструкторы, деструкторы и виртуальные функции, но обычно это зависит от выбора. Рассмотрим простой класс X:
class X {
// ...
X(int);
int m();
friend int f(X&);
};
Внешне не видно никаких причин делать f(X&) другом дополнительно к члену X::m() (или наоборот), чтобы реализовать действия над классом X. Однако член X::m() можно вызывать только для "настоящего объекта", в то время как друг f() может вызываться для объекта, созданного с помощью неявного преобразования типа. Например:
void g()
{
1.m(); // ошибка
f(1); // f(x(1));
}
Поэтому операция, изменяющее состояние объекта, должно быть членом, а не другом. Для определяемых пользователем типов операции, требующие в случае фундаментальных типов операнд lvalue (=, *=, ++ и т.д.), наиболее естественно определяются как члены. И наоборот, если нужно иметь неявное преобразование для всех операндов операции, то реализующая ее функция должна быть другом, а не членом. Это часто имеет место для функций, которые реализуют операции, не требующие при применении к фундаментальным типам lvalue в качестве операндов (+, -, || и т.д.).Если никакие преобразования типа не определены, то оказывается, что нет никаких существенных оснований в пользу члена, если есть друг, который получает ссылочный параметр, и наоборот. В некоторых случаях программист может предпочитать один синтаксис вызова другому. Например, оказывается, что большинство предпочитает для обращения матрицы m запись m.inv(). Конечно, если inv() действительно обращает матрицу m, а не просто возвращает новую матрицу, обратную m, ей следует быть другом.При прочих равных условиях выбирайте, чтобы функция была членом: никто не знает, вдруг когда-нибудь кто-то определит операцию преобразования. Невозможно предсказать, потребуют ли будущие изменения изменить статус объекта. Синтаксис вызова функции члена ясно указывает пользователю, что объект можно изменить; ссылочный параметр является далеко не столь очевидным. Кроме того, выражения в члене могут быть заметно короче выражений в друге. В функции друге надо использовать явный параметр, тогда как в члене можно использовать неявный this. Если только не применяется перегрузка, имена членов обычно короче имен друзей.