
- •Учебное пособие
- •Введение
- •Объектно-ориентированный подход
- •Объектно-ориентированное программирование Абстрактные типы данных
- •Базовые принципы объектно-ориентированного программирования
- •Простейший ввод и вывод
- •Объект cout
- •Манипуляторы hex и oct
- •Другие манипуляторы
- •Объект cin
- •Операторы для динамического выделения и освобождения памяти (new и delete)
- •Базовые конструкции объектно-ориентированных программ Объекты
- •Понятие класса
- •Конструктор копирования
- •Конструктор explicit
- •Указатели на компоненты класса
- •Встроенные функции (спецификатор inline)
- •Организация внешнего доступа к локальным компонентам класса (спецификатор friend)
- •Вложенные классы
- •Static-члены (данные) класса
- •Указатель this
- •Компоненты-функции static и const
- •Proxi-классы
- •Параметры ссылки
- •Независимые ссылки
- •Практические приемы ограничения числа объектов класса
- •Наследование (производные классы)
- •Конструкторы и деструкторы при наследовании
- •Виртуальные функции
- •Абстрактные классы
- •Виртуальные деструкторы
- •Множественное наследование
- •Виртуальное наследование
- •Перегрузка функций
- •Перегрузка операторов
- •Перегрузка бинарного оператора
- •Перегрузка унарного оператора
- •Дружественная функция operator
- •Перегрузка оператора []
- •Перегрузка оператора ()
- •Перегрузка операторов new и delete
- •Преобразование типа
- •Явные преобразования типов
- •Преобразования типов, определенных в программе
- •Шаблоны Параметризированные классы
- •Передача в шаблон класса дополнительных параметров
- •Шаблоны функций
- •Совместное использование шаблонов и наследования
- •Шаблоны класса и friend
- •Некоторые примеры использования шаблона класса Реализация smart-указателя
- •Классы поддерживающие транзакции
- •Задание значений параметров класса по умолчанию
- •Пространства имен
- •Ключевое слово using как директива
- •Ключевое слово using как объявление
- •Псевдоним пространства имен
- •Организация ввода-вывода
- •Состояние потока
- •Строковые потоки
- •Организация работы с файлами
- •Организация файла последовательного доступа
- •Создание файла произвольного доступа
- •Основные функции классов ios, istream, ostream
- •Основы обработки исключительных ситуаций
- •Перенаправление исключительных ситуаций
- •Исключительная ситуация, генерируемая оператором new
- •Генерация исключений в конструкторах
- •Задание собственной функции завершения
- •Спецификации исключительных ситуаций
- •Задание собственного неожиданного обработчика
- •Иерархия исключений стандартной библиотеки
- •Стандартная библиотека шаблонов (stl) Общее понятие о контейнере
- •Общее понятие об итераторе
- •Категории итераторов
- •Основные итераторы
- •Вспомогательные итераторы
- •Операции с итераторами
- •Контейнерные классы Контейнеры последовательностей
- •Контейнер последовательностей vector
- •Контейнер последовательностей list
- •Контейнер последовательностей deque
- •Ассоциативные контейнеры
- •Ассоциативный контейнер multiset
- •Ассоциативный контейнер set
- •Ассоциативный контейнер multimap
- •Ассоциативный контейнер map
- •Адаптеры контейнеров
- •Адаптеры stack
- •Адаптеры queue
- •Адаптеры priority_queue
- •Пассивные и активные итераторы
- •Алгоритмы
- •Алгоритмы сортировки sort, partial_sort, sort_heap
- •Алгоритмы поиска find, find_if, find_end, binary_search
- •Алгоритмы fill, fill_n, generate и generate_n
- •Алгоритмы equal, mismatch и lexicographical_compare
- •Математические алгоритмы
- •Алгоритмы работы с множествами
- •Алгоритмы swap, iter_swap и swap_ranges
- •Алгоритмы copy, copy_backward, merge, unique и reverse
- •Примеры реализации контейнерных классов Связанные списки
- •Реализация односвязного списка
- •Реализация двусвязного списка
- •Реализация двоичного дерева
- •Литература
- •Вопросы по курсу ооп
- •220013, Минск, п.Бровки, 6.
Параметры ссылки
Если требуется предоставить возможность функции изменять значения передаваемых в нее параметров, то в языке С они должны быть объявлены либо глобально, либо работа с ними в функции осуществляется через передаваемые в нее указатели на эти переменные. В С++ аргументы в функцию можно передавать также и через ссылку. Для этого при объявлении функции перед параметром ставится знак &.
#include <iostream.h>
void fun1(int,int);
void fun2(int &,int &);
void main()
{ int i=1,j=2; // i и j – локальные параметры
cout << "\n адрес переменных в main() i = "<<&i<<" j = "<<&j;
cout << "\n i = "<<i<<" j = "<<j;
fun1(i,j);
cout << "\n значение i = "<<i<<" j = "<<j;
fun2(i,j);
cout << "\n значение i = "<<i<<" j = "<<j;
}
void fun1(int i,int j)
{ cout << "\n адрес переменных в fun1() i = "<<&i<<" j = "<<&j;
int a; // при вызове fun1 i и j из main() копируются
a=i; i=j; j=a; // в стек в переменные i и j при возврате в main()
} // они просто теряются
void fun2(int &i,int &j)
{ cout << "\n адрес переменных в fun2() i = "<<&i<<" j = "<<&j;
int a; // здесь используются ссылки на переменные i и j
a=i; i=j; j=a; // из main() (вторые их имена) и т.о. действия в
// функции производятся с теми же переменными i и j
}
В функции fun2 в инструкции
a=i;
не используется операция *. При объявлении параметра-ссылки компилятор С++ определяет его как неявный указатель (ссылку) и обрабатывает соответствующим образом. При вызове функции fun2 ей автоматически передаются адреса переменных i и j. Таким образом, в функцию передаются не значения переменных, а их адреса, благодаря чему функция может модифицировать значения этих переменных. При вызове функции fun2 знак & перед переменными i и j ставить нельзя.
Независимые ссылки
В языке С++ ссылки могут быть использованы не только для реализации механизма передачи параметров в функцию. Они могут быть объявлены в программе наряду с обычными переменными, например:
#include <iostream.h>
void main()
{ int i=1;
int &j=i; // j – ссылка (второе имя) переменной i
cout << "\n адрес переменных i = "<<&i<<" j = "<<&j;
cout << "\n значение i = "<<i<<" j = "<<j;
j=5; //
cout << "\n адрес переменных i = "<<&i<<" j = "<<&j;
cout << "\n значение i = "<<i<<" j = "<<j;
}
В результате работы программы будет получено:
адрес переменных i = 0xадрес1 j = 0xадрес2
значение i = 1 j = 1
адрес переменных i = 0xадрес1 j = 0xадрес2
значение i =5 j = 5
В этом случае компилятор создает временный объект j, которому присваивается адрес ранее созданного объекта i. Далее j может быть использовано как второе имя i.
Практические приемы ограничения числа объектов класса
Иногда для эффективной работы желательно ограничивать число объектов. Пусть, например, разрабатывается класс для принтера. При этом в системе необходимо при множестве клиентов (заданий, объектов класса PrntJob) иметь только один объект (принтер, объект класса Printer). Это может быть достигнуто инкапсуляцией объекта принтер в одну из функций. Все конструкторы класса Printer должны быть закрытые и могут быть вызваны только из открытых методов класса Printer или методов дружественных этому классу. Кроме того, создаваемый объект является статическим, что исключает возможность его повторного создания.
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
class PrntJob; // предварительное объявление
class Printer // класс принтер
{ Printer(){}
Printer(const Printer& obj){};
public:
void Job(PrntJob&); // функция вывода задания
friend Printer& Print(); // функция возвращает ссылку
}; // на объект "принтер"
class PrntJob // класс задание
{ string str;
public:
void get(const string str) // инициализация задания
{this->str=str;}
string& put(){return str;} // возврат ссылки на текущее задание
};
void Printer::Job(PrntJob& obj)
{cout<<obj.put()<<endl;
}
Printer& Print()
{ static Printer pr; // статический объект "принтер"
return pr; // возврат ссылки на объект"принтер"
}
main()
{ PrntJob ob1,ob2;
ob1.get("задание 1");
ob2.get("задание 2");
// cout<<&Print()<<endl; // выодится адрес объекта принтер
Print().Job(ob1);
// cout<<&Print()<<endl;
Print().Job(ob2);
}
В результате работы программы получим:
задание 1
задание 2
Если при этом выводить адреса объекта принтер, создаваемого для вывода первого и второго задания, то получим одинаковые адреса. Следовательно, можно утверждать, что в функции Print создается единственный объект для вывода всех заданий.
Можно поступить иначе, сделав функцию Print статической членом-функцией класса Printer. Это также исключает необходимость использования friend-механизма для функции Print.
class Printer // класс принтер
{ Printer(){}
Printer(const Printer& obj){};
public:
static Printer& Print(); // создание статического объекта принтер
. . .
};
class PrntJob // класс задание
{ . . .
};
Printer& Printer::Print()
{ static Printer pr; // статический объект "принтер"
return pr; // возврат ссылки на объект"принтер"
}
main()
{ . . .
Printer::Print().Job(ob1); // вызов объекта принтера для объекта задания
Printer::Print().Job(ob2);
}