
- •Абстрактные классы.
- •Аргументы функций по умолчанию.
- •Арифметические операции с указателями и с указателями на массивы.
- •Ввод-вывод в символьные массивы.
- •Виртуальные классы. Порядок вызова конструкторов и деструкторов.
- •Виртуальные функции.
- •Виртуальные функции-члены.
- •Виртуальный деструктор. Абстрактные классы.
- •Динамическая память. Указатели и массивы. Ссылочный тип.
- •Доступ к глобальным переменным, скрытым локальными переменными с тем же именем (оператор ::).
- •Доступ к членам базовых классов внутри производного класса.
- •Доступ к элементам массива. Вычисление размера массива. Многомерные массивы.
- •Дружественные классы и функции.
- •Закрытые, защищенные и открытые элементы класса.
- •Иерархия классов. Иерархия наследования классов.
- •Инициализация и разрушение (конструкторы и деструкторы).
- •Инициализация массивов по умолчанию. Явная инициализация массивов.
- •Инициализация безразмерных массивов
- •1. Инкапсуляция
- •2. Полиморфизм
- •3. Наследовние
- •22.Использование new и delete на примере динамических массивов, стеков, очередей.
- •Указатель this
- •Указатели на структуру
- •Массивы структур
- •Классы и объекты. Класс как структура.
- •Классы. Спецификаторы доступа public, protected, private.
- •Константные (const) и изменяемые (mutable) члены класса.
- •Конструктор копирования для контейнерного класса.
- •Конструкторы и деструкторы.
- •Конструкторы и способы обращения к ним.
- •Логические операции. Инкремент и декремент. Арифметические операции.
- •Объявление переменной массива
- •Множественное наследование.
- •Модификатор константы. Модификатор volatile. Модификатор const
- •Модификатор volatile
- •Модификатор const
- •Модификатор volatile
- •Объединения: синтаксис и правила.
- •Объединения: создание простого объединения. Использование enum.
- •41. Объекты стандартного предопределенного потокового ввода-вывода cin, cout, cerr, clog.
- •Объявление переменных указателей. Простые операторы с указателями.
- •Оператор if. Оператор if-else. Вложенные операторы if-else. Оператор if-else-if.
- •If (условие_истинно) оператор; else оператор;
- •If (условие_истинно)
- •Операторы динамического распределения памяти (new, delete).
- •Операции динамического распределения памяти.
- •Операции отношения и логические операции. Условная операция. Операции сравнения (Операции отношений)
- •Логические операции.
- •Операция присваивания. Приоритет операций.
- •Определение первичного класса.
- •Определение переменных указателей. Инициализация указателей.
- •Организация списка объектов различного типа. Техническая реализация
- •Параметризованная очередь. Параметризованный стек. Параметризованное бинарное дерево.
- •Int max_len; /* Максимальная длина стека */
- •Int top; /* Индекс элемента в вершине стека */
- •Параметризованный класс двухсвязного списка.
- •58. Перегрузка операций
- •59. Перегрузка для труктур
- •Передача значений параметров по умолчанию. Передача параметров по ссылке и ссылочные переменные.
- •Передача параметра по ссылке
- •Передача структур в функции. Создание массива структур.
- •63. Подставляемые функции (inline-функции).
- •Преобразования указателей на объекты
- •65. Приведите пример использования enum.
- •66. Приведите пример использования inline-функции.
- •67. Приведите пример использования аргументов функций по умолчанию.
- •68. Приведите пример использования арифметических операции с указателями.
- •69. Приведите пример использования виртуальных функций
- •70. Приведите пример использования вызова функций по значению и вызов по ссылке.
- •71. Приведите пример использования дружественных функции.
- •72. Приведите пример использования конструкторов и деструктора.
- •73.Приведите пример использования массива структур.
- •Приведите пример использования перегрузки функций.
- •81. Приведите пример использования указателей и массивов.
- •82. Приведите пример использования условного оператора
- •83.Приведите пример использования циклов for, while, do-while.
- •84. Приведите пример использования шаблонов функций.
- •Принципы организации позднего связывания.
- •Приоритет переменных с файловой и локальной областями действия. Операция уточнения области действия.
- •Производные классы. Доступ к полям и функциям базового класса.
- •88. Простой класс. Вложенные классы
- •Пространство имен. Операторы namespace и using. Пространство имен
- •Прототипы функций. Вызов функций по значению и вызов по ссылке. Область действия. Рекурсия.
- •91.Работа с файлами последовательного и произвольного доступа.
- •92.92.Переменные
- •Где объявляются переменные
- •Локальные переменные
- •Вопрос 95
- •96 Соглашения об именах
- •Тело класса и составные функции.
- •Указатели на массивы. Указатели на строки.
- •Использование указателя на символьную строку
- •Условный оператор. Оператор switch.
- •Формальные и фактические параметры. Массивы в качестве параметров. Аргумент типа void.
- •Способ передачи параметров в подпрограмму
- •110.Циклы for. Циклы while. Циклы do-while. Разница между циклами.
- •Цикл while ("пока") с постусловием
Ввод-вывод в символьные массивы.
Строка являются массивом символов. Значением строки является указатель на первый ее символ:
char *string = "строка\n";
Здесь указатель на символы string будет содержать адрес первого символа 'c' строки "строка\n", которая размещается в некоторой области памяти, начиная с этого адреса:
Здесь string[3] = = 'о'.
Рассмотрим фрагмент программы:
char buffer[ ] =" "; // Инициализация // строки из 10 пробелов. char *string = buffer; // string указывает на начало буфера. string="проба\n"; // Присваивание!
При инициализации создается строка buffer и в нее помещаются символы (здесь 10 пробелов). Инициализация char *string=buffer устанавливает указатель string на начало этой строки.
Операция же присваивания в последней строке не копирует приведенную строку "проба\n" в массив buffer, а изменяет значение указателя stringтак, что он начинает указывать на строку "проба\n":
Чтобы скопировать строку "проба\n" в buffer, можно поступить так:
char buffer[ ] = " "; char *p ="проба\n"; int i =0; while ( ( buffer[i] = p[i] ) != '\0' ) i++;
Или так: char buffer[ ] = " " char * p = "проба\n"; char * buf = buffer; while (*buf ++ = *p ++ );
Здесь сначала *p копируется в *buf, т.е. символ 'п' копируется по адресу buf, который совпадает с адресом buffer, т.е. buffer[0] становится равен 'п'. Затем происходит увеличение указателей p и buf, что приводит к продвижению по строкам "проба\n" и buffer соответственно. Последний скопированный символ будет '\0', его значение - 0 и оператор while прекратит цикл.
Еще проще воспользоваться библиотечной функцией, прототип которой находится в файле string.h:
strcpy( buffer, "проба\n");
При копировании необходимо обеспечить, чтобы размер памяти, выделенной под buffer, был достаточен для хранения копируемой строки.
Виртуальные базовые классы.
Иногда применение множественного наследования предполагает достаточно тесную связь между
классами, которые рассматриваются как "братские" базовые классы. Такие классы-братья обычно
должны проектироваться совместно. В большинстве случаев для этого не требуется особый стиль
программирования, существенно отличающийся от того, который мы только что рассматривали. Просто
на производный класс возлагается некоторая дополнительная работа. Обычно она сводится к
переопределению одной или нескольких виртуальных функций (см. $$13.2 и $$8.7). В некоторых
случаях классы-братья должны иметь общую информацию. Поскольку С++ - язык со строгим контролем
типов, общность информации возможна только при явном указании того, что является общим в этих
классах. Способом такого указания может служить виртуальный базовый класс.
Виртуальный базовый класс можно использовать для представления "головного" класса, который может
конкретизироваться разными способами:
class window {
// головная информация
virtual void draw();
};
Для простоты рассмотрим только один вид общей информации из класса window - функцию draw().
Можно определять разные более развитые классы, представляющие окна (window). В каждом
определяется своя (более развитая) функция рисования (draw):
class window_w_border : public virtual window {
// класс "окно с рамкой"
// определения, связанные с рамкой
void draw();
};
class window_w_menu : public virtual window {
// класс "окно с меню"
// определения, связанные с меню
void draw();
};
Теперь хотелось бы определить окно с рамкой и меню:
class window_w_border_and_menu
: public virtual window,
public window_w_border,
public window_w_menu {
// класс "окно с рамкой и меню"
void draw();
};
Каждый производный класс добавляет новые свойства окна. Чтобы воспользоваться комбинацией всех
этих свойств, мы должны гарантировать, что один и тот же объект класса window используется для
представления вхождений базового класса window в эти производные классы. Именно это обеспечивает
описание window во всех производных классах как виртуального базового класса.
Можно следующим образом изобразить состав объекта класса window_w_border_and_menu:
Чтобы увидеть разницу между обычным и виртуальным наследованием, сравните этот рисунок с
рисунком из $$6.5, показывающим состав объекта класса satellite. В графе наследования каждый
базовый класс с данным именем, который был указан как виртуальный, будет представлен
единственным объектом этого класса. Напротив, каждый базовый класс, который при описании
наследования не был указан как виртуальный, будет представлен своим собственным объектом.
Виртуальные деструкторы.
Виртуальный деструктор
Практически всегда деструктор делается виртуальным. Делается это для того, чтобы корректно (без утечек памяти) уничтожались объекты не только заданного класса, а и любого производного от него. Например: в игре уровни, звуки и спрайты могут создаваться загрузчиком, а уничтожаться — менеджером памяти, для которого нет разницы между уровнем и спрайтом.
Пусть (на C++) есть тип Father и порождённый от него тип Son:
class Father
{
public:
Father() {}
~Father() {}
};
class Son : public Father
{
public:
int* buffer;
Son() : Father() { buffer = new int[1024]; }
~Son() { delete[] buffer; }
};
Нижеприведённый код является некорректным и приводит к утечке памяти.
Father* object = new Son(); // вызывается Son()
delete object; // вызывается ~Father()!!
Однако, если сделать деструктор Father виртуальным:
class Father
{
public:
Father() {}
virtual ~Father() {}
};
class Son : public Father
{
private:
int* buffer;
public:
Son() : Father() { buffer = new int[1024]; }
~Son() { delete[] buffer; }
};
вызов delete object; приведет в последовательному вызову деструкторов ~Son и ~Father.