
- •Лекция 1 Основы алгоритмизации
- •1.1 Языки программирования
- •1.2 Этапы решения задач на компьютере
- •1.3 Понятие алгоритма и его свойства
- •1.4 Графическое описание алгоритмов. Схемы алгоритмов
- •Блоки для изображения схем алгоритмов и программ
- •1.5 Типы алгоритмов
- •Лекция 2 Начальные сведения о языке
- •2.3 Компиляция и выполнение программы
- •Лекция 3 Имена, переменные и константы
- •3.1 Имена
- •3.2 Переменные
- •3.3 Константы
- •Лекция 4 Операции и выражения
- •4.1 Выражения
- •4.2 Операция присваивания
- •4.3.1 Арифметические операции
- •4.3.2 Операции сравнения
- •4.4 Порядок вычисления выражений
- •Лекция 5 Операторы
- •5.1 Что такое оператор
- •5.1.1 Операторы-выражения
- •5.1.2 Объявления имен
- •5.1.3 Операторы управления
- •5.1.3.1 Условные операторы
- •5.1.3.2 Операторы цикла
- •5.1.3.3 Оператор возврата
- •5.1.3.4 Оператор перехода
- •Лекция 6 Функции
- •6.1 Вызов функций
- •6.2 Имена функций
- •6.3 Необязательные аргументы функций
- •6.4 Рекурсия
- •Лекция 7 Встроенные типы данных
- •7.1 Общая информация
- •7.2 Целые числа
- •7.3 Вещественные числа
- •7.4 Логические величины
- •7.5 Символы и байты
- •7.6 Кодировка, многобайтовые символы
- •7.7 Наборы перечисляемых значений
- •Лекция 8 Классы и объекты
- •8.1 Понятие класса
- •8.2 Определение методов класса
- •8.3 Переопределение операций
- •8.4 Подписи методов и необязательные аргументы
- •8.4.1 Запись классов
- •Лекция 9 Производные типы данных
- •9.1 Массивы
- •9.2 Структуры
- •9.2.1 Битовые поля
- •9.3 Объединения
- •9.4 Указатели
- •9.4.1 Адресная арифметика
- •9.4.2 Связь между массивами и указателями
- •9.4.3 Бестиповый указатель
- •9.4.4 Нулевой указатель
- •9.5 Строки и литералы
- •Лекция 10 Распределение памяти
- •10.1 Автоматические переменные
- •10.2 Статические переменные
- •10.3 Динамическое выделение памяти
- •10.4 Выделение памяти под строки
- •10.5 Рекомендации по использованию указателей и динамического распределения памяти
- •10.6 Ссылки
- •10.6 Распределение памяти при передаче аргументов функции
- •10.6.1 Рекомендации по передаче аргументов
- •Лекция 11 Производные классы, наследование
- •11.1 Виртуальные методы
- •11.1.1 Виртуальные методы и переопределение методов
- •11.2 Преобразование базового и производного классов
- •11.3 Внутреннее и защищенное наследование
- •11.4 Абстрактные классы
- •11.5 Множественное наследование
- •11.5.1 Виртуальное наследование
- •15.2 Проблема использования общих функций и имен
- •15.3 Использование включаемых файлов
- •15.4 Препроцессор
- •15.4.1 Определение макросов
- •Условная компиляция
- •15.4.2 Дополнительные директивы препроцессора
- •Лекция 16 Определение, время жизни и области видимости переменных в больших программах
- •16.1 Файлы и переменные
- •16.1.1 Общие данные
- •16.1.2 Глобальные переменные
- •16.1.3 Повышение надежности обращения к общим данным
- •16.2 Область видимости имен
- •16.3 Оператор определения контекста namespace
- •Лекция 17 Обработка ошибок
- •17.1 Виды ошибок
- •17.2 Возвращаемое значение как признак ошибки
- •17.3 Исключительные ситуации
- •17.3.1 Обработка исключительных ситуаций
- •17.3.2 Примеры обработки исключительных ситуаций
- •Лекция 18 Bвод-вывод
- •18.1 Потоки
- •18.3 Манипуляторы и форматирование ввода-вывода
- •18.4 Строковые потоки
- •18.5 Ввод-вывод файлов
- •Лекция 19 Шаблоны
- •19.1 Назначение шаблонов
- •19.2 Функции-шаблоны
- •19.3 Шаблоны классов
- •19.3.1 "Интеллигентный указатель"
- •19.3.2 Задание свойств класса
- •Список использованных источников
- •Содержание
16.1.3 Повышение надежности обращения к общим данным
Определять глобальную переменную намного удобнее, чем передавать ссылку на генератор случайных чисел в каждый метод и функцию в качестве аргумента. Достаточно описать внешнюю глобальную переменную (включив соответствующий файл заголовков с помощью оператора #include), и генератор становится доступен. Не нужно менять интерфейс, если вдруг понадобится обратиться к генератору. Не следует передавать один и тот же объект в разные функции.
Тем не менее, использование глобальных переменных может привести к ошибкам. В нашем случае с генератором при его использовании нужно твердо помнить, что глобальная переменная уже определена. Простая забывчивость может привести к тому, что будет определен второй объект – генератор случайных чисел, например с именем randomGen. Поскольку с точки зрения правил языка никаких ошибок допущено не было, компиляция пройдет нормально. Однако результат работы программы будет не тот, которого мы ожидаем. (Исходя из определения класса, ответьте, почему).
При составлении программ самым лучшим решением будет то, которое не позволит ошибиться, т.е. неправильная программа не будет компилироваться. Не всегда это возможно, но в данном случае, как и во многих других, соответствующие средства имеются в языке Си++.
Изменим описание класса RandomGenerator:
class RandomGenerator
{
public:
static void Init(unsigned long start);
static unsigned long GetNumber(void);
private:
static unsigned long previousNumber;
};
Определения методов Init и GetNumber не изменятся. Единственное, что надо будет добавить в файл RandomGenerator.cpp, это определение переменной previousNumber:
//
// файл RandomGenerator.cpp
//
#include "RandomGenerator.h"
#include <time.h>
unsigned long RandomGenerator::previousNumber;
. . .
Методы и атрибуты класса, описанные static, существуют независимо от объектов этого класса. Вызов статического метода имеет вид имя_класса::имя_метода, например RandomGenerator::Init(x). У статического метода не существует указателя this, таким образом, он имеет доступ либо к статическим атрибутам класса, либо к атрибутам передаваемых ему в качестве аргументов объектов. Например:
class A
{
public:
static void Method(const A& a);
private:
static int a1;
int a2;
};
void
A::Method(const A& a)
{
int x = a1;
int y = a2;
int z = a.a2;
} // обращение к статическому атрибуту
// ошибка, a2 не определен
// правильно
Статический атрибут класса во многом подобен глобальной переменной, но доступ к нему контролируется классом. Один статический атрибут класса создается в начале программы для всех объектов данного класса (даже если ни одного объекта создано не было). Можно считать, что статический атрибут – это атрибут класса, а не объекта.
Теперь программа, использующая генератор случайных чисел, будет выглядеть так:
// файл main.cpp
#include "RandomGenerator.h"
main()
{
RandomGenerator::Init(1000);
}
void
fun1(void)
{
unsigned long x=RandomGenerator::GetNumber();
. . .
}
// файл class.cpp
#include "RandomGenerator.h"
Class1::Class1()
{
. . .
}
void
fun2()
{
unsigned long x=RandomGenerator::GetNumber();
. . .
}
Такое построение программы и удобно, и надежно. В отличие от глобальной переменной, второй раз определить генератор невозможно – мы и первый-то раз определили его лишь фактом включения класса RandomGenerator в программу, а два раза определить один и тот же класс компилятор нам не позволит.
Разумеется, существуют и другие способы сделать так, чтобы существовал только один объект какого-либо класса.
Кратко суммируем результаты этого параграфа:
Автоматические переменные заново создаются каждый раз, когда управление передается в соответствующую функцию или блок.
Статические и глобальные переменные создаются один раз, в самом начале выполнения программы.
К глобальным переменным можно обращаться из всей программы.
К статическим переменным, определенным вне функций, можно обращаться из всех функций данного файла.
Хотя использовать глобальные переменные иногда удобно, делать это следует с большой осторожностью, поскольку легко допустить ошибку (нет контроля доступа к ним, можно переопределить глобальную переменную).
Статические атрибуты класса существуют в единственном экземпляре и создаются в самом начале выполнения программы. Статические атрибуты применяют тогда, когда нужно иметь одну переменную, к которой могут обращаться все объекты данного класса. Доступ к статическим атрибутам контролируется теми же правилами, что и к обычным атрибутам.
Статические методы класса используются для функций, по сути являющихся глобальными, но логически относящихся к какому-либо классу.