- •Объектно-ориентированное программирование:
- •Содержание
- •Новый тип данных – класс
- •1.2. Доступность компонентов класса
- •1.3. Конструктор и деструктор
- •1.4.4. Статические члены класса
- •1.4. Компоненты-данные и компоненты-функции
- •1.4.1. Данные – члены класса
- •1.4.2. Функции – члены класса
- •1.4.3. Константные компоненты-функции
- •Указатели на компоненты класса
- •1.5.1. Указатели на компоненты-данные
- •1.5.2.Указатели на компоненты-функции
- •1.6. Указатель this
- •1.7. Друзья классов
- •7.1. Дружественная функция
- •1.7.2. Дружественный класс
- •1.8. Определение классов и методов классов
- •2. Наследование
- •2.1. Определение производного класса
- •2.2. Конструкторы и деструкторы производных классов
- •2.3. Виртуальные функции
- •2.4. Абстрактные классы
- •2.5. Включение объектов
- •2.6. Включение и наследование
- •2.7. Множественное наследование
- •2.8. Локальные и вложенные классы
- •2.9. Пример программы для Microsoft Visual Studio
- •2.10. Упражнения
- •3. Перегрузка операций
- •3.1. Перегрузка унарных операций
- •3.2. Перегрузка бинарных операций
- •3.4. Перегрузка операции вызова функции
- •3.5. Перегрузка операции присваивания
- •3.6. Перегрузка операции new
- •3.7. Перегрузка операции delete.
- •3.8. Основные правила перегрузки операций
- •3.9. Примеры программ
- •4. Шаблоны функций и классов
- •4.1. Шаблоны функций
- •4.2. Шаблоны классов
- •4.3. Компонентные функции параметризованных классов
- •4.4. Примеры программ.
- •5. Обработка исключительных ситуаций
- •5.2. Получение дополнительной информации об исключении
- •5.3. Определение типа исключения
- •5.4. Иерархия исключений
- •5.5. Спецификация функций, обрабатывающих исключения
- •6. Потоковые классы
- •6.1. Библиотека потоковых классов
- •6.3. Стандартные потоки ввода-вывода
- •6.4. Форматирование
- •6.5. Манипуляторы
- •6.6. Ввод-вывод объектов пользовательских классов
- •6.7. Определение пользовательских манипуляторов
- •6.8. Пользовательские манипуляторы с параметрами
- •6.9. Использование макросов для создания манипуляторов
- •6.10. Состояние потока
- •6.11. Неформатированный ввод-вывод
- •6.12. Файловый ввод-вывод
- •7.1. Пространство имен
- •7.2. Динамическая идентификация типов
- •7.3. Безопасное приведение типа
- •8. Стандартная библиотека шаблонов
- •8.1. Введение в stl
- •Парадигму обобщенного программирования можно сформулировать следующим образом:
- •8.2. Итераторы
- •8.3. Классы-контейнеры
- •Iterator find(const key_type&k)
- •Iterator lower_bound(const key_type&k)
- •Iterator upper_bound(const key_type&k)
- •8.4. Контейнер vector
- •8.5. Многомерные массивы
- •8.6. Ассоциативные контейнеры
- •8.7. Объекты-функции
- •8.8. Алгоритмы
- •I. Немодифицирующие операции
- •II. Модифицирующие операции
- •III. Сортировка
- •IV. Работа с множествами
- •V. Минимумы и максимумы
- •VI. Перестановки
2.10. Упражнения
Упражнение 1. В этом упражнении мы покажем, что функции-члены базового и производного классов не составляют множество перегруженных функций, т.е. функция set класса CDerived скрывает видимость функции-члена CBase::set, а не перегружает ее. Вызов функции-члена базового класса из производного в этом случае приводит к ошибке при компиляции.
В среде Microsoft Visual C++ создайте следующую программу и попытайтесь ее откомпилировать.
#include<iostream.h>
class CBase
{
protected:
int x;
public:
CBase(int);
void print();
void set(int);
};
CBase::CBase(int X):x(X){}
void CBase::print(){cout<<x<<endl;}
void CBase::set(int X){x=X;}
class CDerived:public CBase
{
protected:
int y;
public:
CDerived(int,int);
void print();
void set(int,int);
};
CDerived::CDerived(int X,int Y):CBase(X),y(Y){}
void CDerived::print(){cout<<x<<' '<<y<<endl;}
void CDerived::set(int X,int Y){x=X;y=Y;}
int main()
{
CDerived ob(5,6);
ob.set(7,8);
ob.print();
ob.set(9);// Ошибка компиляции
ob.print();
ob.CBase::print();
return 0;
}
При компиляции выделенной строки вы получите сообщение:
Compiling...
error C2660: 'set' : function does not take 1 parameters
Error executing cl.exe.
Замените ошибочную строку строкой b.set(9);
на ob.CBase::set(9); откомпилируйте и выполните программу, и вы увидите, что она выполняется без ошибки.
Результат выполнения посмотрите здесь inh1.exe
Другой способ решения этой проблемы–написать в производном классе небольшую встроенную функцию заглушку для вызова функции базового класса.
class CDerived:public CBase
{
protected:
int y;
public:
CDerived(int,int);
void print();
void set(int,int);
void bset(int i){CBase::set(i);} //Функция-заглушка
};
Выполнив
int main()
{
CDerived ob(5,6);
ob.set(7,8);
ob.print();
ob.bset(9); //
ob.print();
ob.CBase::print();
system("pause");
return 0;
}
Вызов ob.bset(9); дает тот же результат, что и ob.CBase::set(9);
Упражнение 2. В этом упражнении мы покажем использование виртуальных функций.
Создадим иерархию классов: «птицы» имеют свойство «летать» и наследуемый класс «пингвин», который летать не умеет.
#include<iostream.h>
//птицы
class bird{
//...
public:
void fly()const{cout<<"fly"<<endl;} //может летать
//Если не const, то при вызове в функции alarm() b.fly();
// сообщение
//cannot convert 'this' pointer from 'const class bird' to 'class bird &'
};
//пингвин
class penguin:public bird{
//...
public:
// Переопределяем, чтобы пингвин не летал
void fly()const{cout<<"nofly"<<endl;}
};
int main()
{
bird b;
penguin p;
b.fly();//летит
p.fly();//не летит
return 0;
}
Создадим и выполним эту программу. Все нормально: птицы летают, но пингвин не летает.
Усложним задание. Добавим функцию alarm() – сигнал «тревога», который поступает всем птицам, в том числе и пингвину. Реакция птиц на сигнал «тревога» : убежать, улететь.
#include<iostream.h>
//птицы
class bird{
//...
public:
void fly()const{cout<<"fly"<<endl; }
};
//пингвин
class penguin:public bird{
//...
public:
void fly()const{cout<<"nofly"<<endl;}
};
//Сигнал тревоги
void alarm(const bird& b)
{
b.fly();
}
int main()
{
bird b;
penguin p;
b.fly();//летит
p.fly();//не летит
alarm(b);//полетела
alarm(p);//как ни странно, и пингвин полетел
return 0;
}
Создадим и выполним эту программу. Видим, что все птицы, в том числе и пингвин, летят.
Сделаем функцию fly() виртуальной.
virtual void fly()const{cout<<"fly"<<endl;
Создадим и выполним эту программу. Все нормально: птицы летают, но пингвин не летает.
int main()
{
bird b;
penguin p;
b.fly();//летит
p.fly();//не летит
alarm(b);//полетела
alarm(p);//не летит, а только бежит
return 0;
}
Более грамотным решением будет создание абстрактного класса «птицы» с абстрактной виртуальной функцией fly(). В конкретном классе птиц эта функция переопределяется должным образом.
#include<iostream.h>
// Абстрактный класс-птицы
class bird{
//...
public:
virtual void fly()const=0;//Абстрактный метод-
//должен быть переопределен в производных классах
};
//ворона
class crow:public bird{
//...
public:
//Ворона летает
void fly()const{cout<<"fly"<<endl;}
};
//пингвин
class penguin:public bird{
//...
public:
//Пингвин не летает
void fly()const{cout<<"nofly"<<endl;}
};
//Сигнал тревоги
void alarm(const bird& b)
{
b.fly();
}
int main()
{
crow c;
penguin p;
c.fly(); // летит
p.fly(); //не летит
alarm(c); //полетела
alarm(p); //не летит, а бежит
return 0;
}
