- •Экзамен 374 Предварительные рассуждения Вступительное слово
- •Исторические факты
- •Начнем!
- •Проба пера
- •Открытие сохраненного проекта
- •Вывод данных
- •Типы данных
- •Хороший стиль программирования
- •Переменные и константы
- •Практический пример
- •Ввод данных
- •Например:
- •Пример:
- •Арифметические операции с числами
- •Литералы
- •Некоторые примеры
- •Домашнее задание
- •Напишите программу, которая вводит число из трех цифр, разделяет число на отдельные цифры и печатает их отдельно друг от друга с тремя пробелами между ними. Преобразование типов
- •Перечисляемые типы
- •Типичная ошибка
- •Хороший стиль программирования
- •Типичная ошибка
- •Выражения
- •Оператор if
- •Структура программы
- •Логические операции
- •Структура множественного выбора switch
- •Практический пример
- •Цикл for
- •Практический пример
- •Цикл do-while
- •Домашнее задание
- •Вызов функции
- •Прототипы функций
- •Разбор программы
- •Область видимости
- •Аргументы по умолчанию
- •Встраивание
- •Перегрузка функций
- •Учебный пример перегруженных функций. Иллюстрация перегрузки
- •Результат работы программы
- •Практические примеры
- •Домашнее задание
- •Примеры домашней работы урока 1 Пример №1
- •Как работает программа
- •Пример №2
- •Как работает программа
- •Примеры домашних работ на создание функций Пример №1
- •Как работает программа
- •Пример №2
- •Как работает программа
- •Массивы
- •Объявление массивов
- •Примеры использования массивов
- •Программа 1
- •Программа 2
- •Обратите внимание!
- •Типичная ошибка программирования
- •Типичная ошибка программирования
- •Программа 3
- •Типичная ошибка программирования
- •Замечание по технике программирования
- •Программа 4
- •Программа 5
- •Программа нахождения минимального и максимального элементов массива
- •Сортировка массивов
- •Домашнее задание
- •Что такое указатели?
- •За кулисами...
- •Как работать с указателями?..
- •Зачем нужны указатели?
- •Указатели и Массивы.
- •Примеры задач
- •Пример 1
- •Пример 2
- •Пример 3
- •Указатели - аргументы функций.
- •Ссылочные параметры
- •Примеры решения задач
- •Домашнее задание
- •Операторы свободной памяти new и delete
- •Функции работы со строками из библиотеки обработки строк
- •Пример 1.
- •Пример2
- •Пример 3
- •Пример задачи на новый материал
- •Домашнее задание
- •Двухмерные массивы, как частный случай многомерных массивов
- •Программа.
- •Результаты работы программы.
- •Многомерные динамические массивы
- •Пример на многомерные динамические массивы
- •Домашнее задание
- •Рекурсия
- •Рекурсии или итерации
- •Указатели на функции
- •Пример №1
- •Результат выполнения программы:
- •Пример №2
- •Результат выполнения программы
- •Пример №3
- •Результаты выполнения программы
- •Определения структур
- •Пример #1 на использование структур
- •Пример #2 на использование структур
- •Оператор указателя на структуру
- •Домашнее задание
- •Тест по c Группа ___________________ф. И. О. ______________________
- •Объектно-ориентированное программирование.
- •Наследование (Inheritance).
- •Инкапсуляция (Encapsulation).
- •Определение класса
- •Конструкторы и деструкторы Инициализация объектов класса: конструкторы
- •Основное назначение конструкторов - инициализация объектов.
- •Использование конструкторов с аргументами по умолчанию
- •Если параметры не передаются конструктору, в определении объекта не нужно включать пустые круглые скобки.
- •Использование деструкторов
- •Когда вызываются конструкторы и деструкторы.
- •Домашнее задание
- •Конструктор копирования
- •Синтаксис конструктора копирования
- •Памятка
- •Пример использования конструктора копирования.
- •Перегруженные конструкторы
- •Экскурс в историю
- •Послесловие к примеру
- •Маленькое замечание
- •Домашнее задание
- •Создание класса ''строка''
- •Перегрузка операций.
- •Общие принципы перегрузки операторов.
- •Преобразования, определяемые классом
- •Пример строкового класса с перегруженными операторами
- •Домашнее задание
- •Дружественные функции (Friend Functions)
- •Пример строкового класса с перегруженными операторами и дружественными функциями
- •Перегрузка операторов new и delete
- •Перегрузка оператора индексирования
- •Класс вектор. Часть1.
- •Класс вектор. Часть 2.
- •Класс вектор. Часть 3.
- •Домашнее задание
- •Наследование (Inheritance). Часть 1.
- •Наследование (Inheritance). Часть 2.
- •Множественное наследование (multiple inheritance)
- •Пример множественного наследования
- •Домашнее задание
- •Статические члены данных
- •Раннее и позднее связывание
- •Виртуальные функции
- •Пример.
- •Абстрактные классы
- •Виртуальный базовый класс
- •Практический пример
- •Домашнее задание
- •Потоки ввода-вывода.
- •Iostream.H: stream - поток, "I" - сокр. Input - ввод, "o" - сокр. Output - вывод.
- •Предопределенные потоки.
- •Операции помещения в поток и извлечения из потока.
- •Файловый ввод-вывод с применением потоков.
- •Конструкторы файловых потоков.
- •Функции для открытия и закрытия файлов.
- •Функции для обмена с потоками.
- •Часто применяемые функции потока.
- •Ввод/вывод массива в/из файл(-а).
- •Практический пример: перекодировка файла.
- •Домашнее задание
- •Немного о файлах...
- •И снова файлы...
- •Пример "Телефонная книга"
- •Файл abonent.H
- •Форматирование данных при обменах с потоками.
- •Состояние потока.
- •Использование аргументов командной строки.
- •Ввод/вывод в с.
- •Домашнее задание
- •Определение шаблонов функций
- •Переопределение шаблонов функций
- •Шаблоны классов
- •Шаблонный класс вектор
- •Шаблонный класс вектор
- •Шаблонный класс вектор
- •Введение
- •Обработка исключительных ситуаций
- •Практический пример
- •Программа
- •Домашнее задание
- •Экзамен
Перегруженные конструкторы
Итак продолжаем подвиги на стезе обучения !!! Первым пунктом нашей программы будут Перегруженные конструкторы. К этому моменту вы уже знаете этих 2 слова по отдельности и иногда можете попугать знакомых ими.
Экскурс в историю
Разные функции могут иметь одно и то же имя, если у этих функций различны количество и/или типы параметров. Это называется перегрузкой функции. А сами функции перегруженными. Обрабатывая вызов перегруженной функции, компилятор смотрит не только на ее имя, но и на список параметров. По количеству и типам передаваемых параметров компилятор может определить, какую же из одноименных функций нужно вызывать в данном случае.
Пример
//Предположим у вас возникла необходимость написать программу для ввода
//чисел разного типа. Перед вводом числа будет выдаваться подсказка о
//вводимом типе. Это эффектно реализуется с помощью перегрузки !!!
#include <iostream.h>
//У нас есть перегруженная функция под названием EnterDigit, которая
//принимает 2 параметра . Существует 2 определения этой функции:
//В первой версии , принимаемые аргументы - это char * и int & .
//В второй версии char * и double & .
//В зависимости от типа переданных значений вызывается соответствующая
//версия .
void EnterDigit (char *str , int &i){
cout<<str;
cin>>i;
}
void EnterDigit (char *str , double &i){
cout<<str;
cin>>i;
}
void main(){
int i;
double d;
//Вызов версии void EnterDigit (char *str , int &i)
// так как второй параметр имеет тип int
EnterDigit("Enter an integer :",i);
//Вызов версии void EnterDigit (char *str , int &i)
// так как второй параметр имеет тип double
EnterDigit("Enter a double :",d);
//Вывод результатов на экран
cout<<i<<" "<<d;
}
Послесловие к примеру
Итак мы рассмотрели пример на перегрузку функций . Я надеюсь вы вспомнили,что такое перегруженная функция и с чем её едят.
Маленькое замечание
Хотя можно использовать одно и то же имя для перегрузки функций, выполняющих совершенно разные действия, делать этого не стоит. Так как смысл перегрузки - выполнение схожих действий.
Конец экскурса
О конструкторах вы читали в предыдущем урок.Конструктор - тоже функция отсюда следует вывод !!! Его можно перегрузить . При этом на его перегрузку будут распостраняться все те же правила, которые используются при обычной перегрузке функций .Возникает вопрос , а зачем мне собственно говоря перегружать конструктор ? Для того чтобы при создании обьекта класса вы могли предусмотреть различные способы инициализации .
Пример
//Напишем класс таймер с перегруженным конструктором.
#include <iostream.h>
#include <stdlib.h>
// В библиотеке stdlib.h находится функция
// atoi (её прототип int atoi( const char *string ) ) ,
// которая конвертирует строку в число. Строка задаётся в качестве
// параметра , возвращаемое значение и будет полученным числом
// Ниже у нас определено 3 версии перегруженного конструктора, которые
// охватывают все возможные случаи инициализации .
class timer {
int seconds;
public:
// Первый перегруженный конструктор предназначен для инициализации
// обьекта с помощью строки
timer(char *t){
seconds=atoi(t);
cout<<" char * "<< "\n";
}
// Второй перегруженный конструктор предназначен для инициализации
// обьекта с помощью целого числа
timer(int t){
seconds=t;
cout<<" int "<< "\n";
}
// Третий перегруженный конструктор предназначен для инициализации
// обьекта с помощью 2 целых чисел ( минут и секунд )
timer(int min,int sec){
seconds=min*60+sec;
cout<<" int , int "<< "\n";
}
// Функция для показа количества секунд
void ShowTime(){
cout<<"Seconds : "<<seconds<<"\n";
}
};
void main(){
// Обьявления переменных
//Строковый массив для хранения секунд
char s[20];
//Переменная целого типа для хранения секунд
int sec;
//Переменная целого типа для хранения минут
int min;
// Ввод секунд в строковую переменную
cout<< "Put seconds : "<<" \n ";
cin>> s ;
// Ввод секунд в переменную целого типа
cout<< "Put seconds one more time : "<<" \n ";
cin>> sec ;
// Ввод минут в переменную целого типа
cout<< "Put minutes : "<<" \n ";
cin>> min ;
// Создание 3-х обьектов класса таймер
timer a(s), b(sec), c( min, sec);
// Показ значений секунд
a.ShowTime();
b.ShowTime();
c.ShowTime();
}
Вывод
Использование перегруженных конструкторов необходимо тогда , когда нужно предусмотреть все возможные формы инициализации при создании обьекта .
this
С каждым занятием мы все глубже и глубже проникаемся идеями объектно-ориентированого программирования. Мы уже знаем как описать класс, как использовать модификаторы доступа. Сегодня, мы рассмотрим еще один важный вопрос, который касается объектно-ориентированого программирования - указатель this. Заметим, что это один из сложнейших вопросов, который рассматривается в ООП. Поэтому отниситесь к данной теме со всей серьезностью.
Как показывает практика, многие реальные задачи из жизни требуют того, чтобы в протоколе описания класса существовала возможность вызова функции-члена внутри определения другой функции-члена. Если последовательно придерживаться объектно-ориентированной парадигмы, то вложенный вызов функции должен интерпретироваться как передача сообщения объекту (если Вы забыли что такое сообщение, загляните в первое занятие посвященное ООП). Объект, принимающий вложенное сообщение - это тот же самый объект, который обрабатывает сообщение, представленное вызовом внешней функции.
Вложенный вызов функции в объектно-ориентированных языках интерпретируется как передача сообщения самому себе, что должно быть явно указано. В С++ для представления термина "сам себе" используется ключевое слово this. Таким образом, ключевое слово this используется для обозначения указателя на объект, который сгенерировал обращение к функции-члену. Всем функциям-членам указатель this передается автоматически.
Ключевое слово this обозначает объявленный неявно указатель на себя. Другими словами, при реализации функций-членов класса, мы работаем с данными так, как будто они передаются через указатель this. Особенностью this является то, что он предоставляет встроенный не требующий объявления указатель. Другими словами, например, это то же самое, как если бы в классе Test неявно объявлялся закрытый член Test* const this. Заметим, что указатель this изменить нельзя. Обычно указатель this используется неявно, но в некоторых ситуациях желательно его явное использование, причем, использование this не отличается от использования любого другого указателя.
Рассмотрим пример использования this. Ниже приведена тестовая программа, где создается класс Test в котором: объявлены два поля данных (с1 и с2); есть конструктор Test(char b) в котором происходит инициализация полей данных; функция-член Print(), которая позволяет вывести на экран содержимое полей данных (т.е. с1 и с2); функция-член Increment использует неявный указатель this, чтобы возвратить приращенные значения c1 и c2; а функция-член Where_Am_I возвращает адрес заданного объекта.
#include <iostream.h>
/*Демонстрация использования указателя this*/
class Test{
public:
//конструктор
Test(char b)
{
c1=b;
c2=c1+1;
}
//функция увеличения
Test Increment()
{
c1++;
c2++;
return (*this);//вернуть объект
}
//функция возвращает адрес памяти где расположен наш объект
Test* Where_Am_I()
{
return this;//вернуть указатель на себя
}
//функция печати
void Print()
{
cout<<c1<<c2<<'\t';
}
private:
char c1,c2;
};
void main()
{
Test a('A');//создадим экземпляр класса Test
a.Print();//выведем на экран значение полей данных
//узнаем где мы (т.е.выведем адреса памяти, где расположен наш объект)
cout<<"is at"<<a.Where_Am_I()<<endl;
Test b('B');//создадим экземпляр класса Test
b.Print();//выведем на экран значение полей данных
//узнаем где мы (т.е.выведем адреса памяти, где расположен наш объект)
cout<<"is at"<<b.Where_Am_I()<<endl;
//вызываем функцию-член Increment()
//так как функция возвращает экземпляр класса, то можем обратиться
//к функции-члену Print
b.Increment().Print();
}
Результат работы программы следующий:
AB is at0x0065FDF4
BC is at0x0065FDF0
CD Press any key to continue
Теперь снова вернемся к вопросу о перегрузке операторов. Обратите внимание, что при перегрузке унарного оператора список параметров операции-функции может быть пустым, так как параметр передается неявным образом в указателе this. При перегрузке бинарного оператора, список параметров операции-функции задает один операнд справа от оператора, так как операнд слева передается неявным образом, снова таки, в указателе this. Чтобы разобраться во всех тонкостях использования this, давайте рассмотрим пример строкового класса с перегруженными операторами.