- •Базовое ядро языка Элементы программы.
- •Комментарии
- •Инструкция – выражение
- •Инструкция
- •Определение функции
- •Заголовок функции
- •Прототипы функций
- •Аргументы по умолчанию.
- •Перегрузка функций
- •Встраиваемые функции
- •Стек до блока Вошли в блок Вышли из блока
- •Индексирование
- •Int a [100]; одномерный массив
- •Int b [3][5]; двухмерный массив
- •Int c [7][9][2]; трехмерный массив
- •Передача массивов функциям
- •Объявления ссылок и вызовов по ссылке
- •Функции-члены класса
- •Доступ: закрытый и открытый
- •Область видимости класса
- •Оператор разрешения области видимости ::
- •Вложенные классы
- •Статические члены данных
- •Указатель this
- •Функции-члены типа static и const.
- •Изменчивость (mutable)
- •Создание и уничтожение объектов
- •Классы с конструкторами
- •Конструкторы как преобразования
- •Создание динамического стека
- •Классы с деструкторами
- •Пример: динамически размещаемые строки
- •Ad hoc полиморфизм
- •Алгоритм выбора перегруженной функции
- •Перегрузка операторов
- •Перегрузка бинарных операторов
- •Перегрузка операторов присваивания и индексирования
- •Перегруженные операторы ввода-вывода « и »
- •Перегрузка оператора ( ) для индексирования
- •Операторы указателей
- •Указатель на член класса
- •Перегрузка new и delete
- •Наследование.
- •Методология объективно-ориентированного проектирования
- •Виртуальные функции
- •Абстрактные базовые классы
Конструкторы как преобразования
Конструктор с единственным параметром автоматически является функцией преобразования, если только он не объявлен с ключевым словом explicit. Рассмотрим следующий класс, назначение которого — напечатать невидимые символы с их представлением ASCII; например, код с восьмеричным номером 07 — это звонок (звуковой сигнал).
class pr_char { public: pr_char(int i = 0) : c(i % 128) {}
void print() const { cout <<rep[c];}
private: int c; static const char* rep(128]; };
const char* pr_char::rep[128] = { "nul", "soh", "stx",
.......
" w ", " x "," y ", "z ", "{"," | ", " } ", " ~", " de1"};int main ()
{ pr_char с ; for (int i = 0; i < 128; ++i) { с = i; //или: c=static_cast<pr_char>(i)
c.print() ; cout << endl ; } }
Конструктор выполняет автоматическое преобразование типа int в тип pr_char. Отметьте, что инструкция в цикле
c = i; как раз и заключает в себе это преобразование.
Создание динамического стека
Конструктор можно также использовать для выделения пространства из свободной памяти.
//Реализация ch_stack с конструктором
class ch_stack { public:
//открытый интерфейс для АТД ch_stack
explicit ch_stack(int size) : max_len(size), top(EMPTY)
{ assert(size > 0); s = new char[size]; assert(s != 0);}
void reset () { top = EMPTY; }
void push(char c) { s[++top] = c; }
char pop() { return s[top--]; }
char top_of() const { return s[top]; }
bool empty() const { return (top = = EMPTY); }
bool full() const { return (top = = max_len - 1); }
private:
enum { EMPTY = -1 };
char* s; //было s[max_len]
int max_len;
int top;
};
Теперь клиент, использующий ch_stack, может выбрать требуемый размер. Пример объявления ch_stack с вызовом конструктора выглядит так:
ch_stack data(l000); //размещение 1000 элементов
ch_stack more_data(2 * n) ; //размещение 2*п элементов
Копирующий конструктор
Рассмотрим наш стек и подсчитаем, сколько раз встречается заданный символ. Можно многократно извлекать элементы из стека, проверяя каждый из них по очереди, до тех пор пока стек не будет пуст. Но что если мы хотим сохранить нетронутым содержимое стека? Вызываемые по значению параметры именно это и выполняют:
int cnt_char(char с, ch_stack s)
{int count = 0; while (! s.empty()) count += (c = = s.pop());
return count; }
Семантика вызова по значению требует, чтобы была создана локальная копия аргумента, и чтобы она была инициализована значением выражения, переданного в качестве фактического параметра. необходим копирующий конструктор (сорy constructor). Компилятор предоставляет копирующий конструктор по умолчанию. Его сигнатура такова:
ch_stack::ch_stack(const ch_stack&);
Классы с деструкторами
Деструктор — это функция-член, имя которой представляет собой начинающееся с тильды имя класса. Почти всегда он вызывается неявно — при выходе из блока, в котором был объявлен объект. Деструктор также вызывается, когда оператор delete применяется к указателю на имеющий деструктор объект, или когда он необходим для уничтожения подобъекта удаляемого объекта.
Добавление деструктора позволяет классу вернуть во время выполнения программы ненужную более память, выделенную из кучи. Все открытые функции-члены работают совершенно также, как раньше. Отличие состоит в том, что при выходе из блока или функции для очистки памяти будет неявно вызван деструктор. Это хорошая программистская практика, благодаря которой приложение требует меньше памяти.