
- •Учебное пособие
- •Введение
- •Объектно-ориентированный подход
- •Объектно-ориентированное программирование Абстрактные типы данных
- •Базовые принципы объектно-ориентированного программирования
- •Простейший ввод и вывод
- •Объект 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.
Множественное наследование
В языке С++ имеется возможность образовывать производный класс от нескольких базовых классов. Общая форма множественного наследования имеет вид:
class имя_произв_класса : имя_базового_кл 1,…,имя_базового_кл N
{ содержимое класса
};
Иерархическая структура, в которой производный класс наследует от несколько базовых классов, называется множественным наследованием. В этом случае производный класс, имея собственные компоненты, имеет доступ к protected- и public-компонентам базовых классов.
Конструкторы базовых классов при создании объекта производного класса вызываются в том порядке, в котором они указаны в списке при объявлении производного класса.
При применении множественного наследования возможно возникновение нескольких конфликтных ситуаций. Первая - конфликт имен методов или атрибутов нескольких базовых классов:
class A
{public: void fun(){}
};
class B
{public: void fun(){}
};
class C : public A, public B
{ };
main()
{ C *c=new C;
c->fun(); // error C::f' is ambiguous
return 0;
}
При таком вызове функции fun() компилятор не может определить, к какой из двух функций классов A и B выполняется обращение. Неоднозначность можно устранить, явно указав, какому из базовых классов принадлежит вызываемая функция:
c->A:: fun(); или c->B::fun();
Вторая проблема возникает при многократном включении некоторого базового класса:
#include "iostream.h"
#include "string.h"
class A // БАЗОВЫЙ класс I уровня
{ char naz[20]; // название фирмы
public:
A(char *NAZ) {strcmp(naz,NAZ);}
~A() {cout << "деструктор класса А" << endl;}
void a_prnt() {cout << naz << endl;}
};
class B1 : public A // ПРОИЗВОДНЫЙ класс (1 Базовый II уровня)
{ protected:
long tn;
int nom;
public:
B1(char *NAZ,long TN,int NOM): A(NAZ),tn(TN),nom(NOM) {};
~B1() {cout << "деструктор класса В1" << endl;}
void b1_prnt()
{ A::a_prnt();
cout << " таб. N " << tn <<" подразделение = " << nom <<endl;
}
};
class B2 : public A // ПРОИЗВОДНЫЙ класс (2 Базовый II уровня)
{ protected:
double zp;
public:
B2(char *NAZ,double ZP): A(NAZ),zp(ZP) {};
~B2(){cout << "деструктор класса В2" << endl;}
void b2_prnt()
{ A::a_prnt();
cout << " зар/плата = " << zp << endl;
}
};
class C : public B1, public B2 // ПРОИЗВОДНЫЙ класс ( III уровня)
{ char *fam;
public:
C(char *FAM,char *NAZ,long TN,int NOM,double ZP) :
B1(NAZ,TN,NOM), B2(NAZ,ZP)
{ fam = new char[strlen(FAM)+1]
strcpy(fam,FAM);
};
~C() {cout << "деструктор класса С" << endl;}
void c_prnt()
{ B1::b1_prnt();
B2::b2_prnt();
cout << " фамилия " << fam<<endl;
}
};
void main()
{ C cc("Иванов","мастра",1234,2,555.6),*pt=&cc;
// cc.a_prnt(); ошибка 'C::a_prnt' is ambiguous
// pt->a_prnt();
cc.b1_prnt();
pt->b1_prnt();
cc.b2_prnt();
pt->b2_prnt();
cc.c_prnt();
pt->c_prnt();
}
В приведенном примере производный класс С имеет по цепочке два одинаковых базовых класса А (A<-B1<-C и A<-B2<-C), для каждого базового класса А строится свой объект (рис. 3, 4). Таким образом, вызов функции
cc.a_prnt();
pt->a_prnt();
некорректен, так как неизвестно, какую из двух функций (какого из двух классов А) требуется вызвать.