3. Наследование и полиморфизм. (Семинары)
Описание файла
Файл "3. Наследование и полиморфизм." внутри архива находится в папке "Семинары". PDF-файл из архива "Семинары", который расположен в категории "". Всё это находится в предмете "информатика" из 2 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст из PDF
Кафедра Компьютерных методов физики: программирование, первый курс, второй семестрЯзык программирования Си++Иванов А.П., Князева О.С.Семинар 3. Наследование и полиморфизмДля эффективной разработки программ удобно использовать иерархическое упорядочениепонятий и объектов. Такое упорядочение позволяет легче справляться со сложностьюразрабатываемых программ, сделать логику их работы более простой и понятной.Иерархия понятий реализуется в виде древовидной структуры, в основе которой лежитнаиболее общее понятие.
В языке Си++ подобная структура реализуется через механизмпроизводных классов, наследующих свойства базовых классов.Производные классы – развитие классов, определенных ранее, имеющие доступ кprotected и public части базового класса. Производные классы наследуют всесвойства базовых классов, при этом некоторые свойства могут быть запрещены кнаследованию, другие – можно изменить при наследовании, а третьи – могут бытьдобавлены к свойствам базового класса.1. Права доступа к членам базового классаПрава доступа к членам базового класса из производного класса определяютсямодификатором доступа, задаваемом при описании производного класса.class Base {private:..............protected:..............public:..............} ;class Derived : public Base { // здесь может применяться private и protectedpublic:..............};Естественно, нет никаких ограничений на состав функций и полей данных, определяемыхв производном классе дополнительно по отношению к базовому.Таблица прав доступа к членам базового класса в производном классеМодификатор доступа,указанный принаследованииprivateprotectedpublic07.11.2011Право доступа в базовомклассеprivateprotectedpublicprivateprotectedpublicprivateprotectedpublicНаследуемое право доступа впроизводном классене доступенprivateprivateне доступенprotectedprotectedне доступенprotectedpublic1Кафедра Компьютерных методов физики: программирование, первый курс, второй семестр2.
Дружественные функции и классыВ ряде случаев бывает удобно получить доступ к приватным и защищенным (private,protected) членам класса из функций, не являющихся членами этого класса. Для того втело класса нужно вставить прототип такой функции, и перед ним поставить ключевоеслово friend.В тех случаях, когда классы тесно «взаимодействуют» друг с другом (то есть, когдаобъекты одного класса являются аргументами членов функции другого класса) бываетудобно разрешить доступ таким классам к приватным и защищенным (private,protected) членам этих классов.
Для этого в теле класса, к членам которогооткрывается доступ, нужно описать класс, получающий доступ, с ключевым словомfriend.Отметим, что помимо воли автора этого класса получить доступ к его защищенным полями методам – нельзя, то есть, чтобы этот доступ получить – в нем самом нужно сделатьдополнительное объявление дружественных классов или функций.#include <ostream>class CVector {private:intdim; // размерность вектораfloat *ptr;// указатель на область памяти, содержащуювектора.private:...// дружественный оператор вывода:friend ostream& operator<< (ostream& os, const CVector &v);friend class CMatrix; // дружественный класс...};элементыostream& operator<< (ostream& os, const CVector &v){for (int n=0; n < v.dim; n++) {os << "[" << n << "] " << v.ptr[n] << endl;}return os;}class CMatrix {private:intcx, cy;float *ptr;//размерности матрицы// указатель на память, содержащую элементы матрицыpublic:...// оператор умножения матрицы на вектор:CVector& operator * (CVector &v);...};07.11.20112Кафедра Компьютерных методов физики: программирование, первый курс, второй семестр3.
Перегрузка при наследованииВ производных классах могут существовать функции-члены базового класса с именем,совпадающим с именем какой-либо функции базового класса.class Base {...public:void mf(void) { cout << 1; }} ;class Derived : public Base {...public:void mf(void) { cout << 2; }};Basex;Derived y;...x.mf(); // 1, вызывается функция базового класса Basey.mf(); // 2, вызывается функция производного класса Derived;4.
Полиморфизм: виртуальные методы классаПозволяют выбирать методы с одним и тем же именем через указатель функции взависимости от типа реального объекта, на который указывает указатель, а не взависимости от типа указателя.class Base {...public:virtual void mf(void) { cout << 1; }void mfstd(void) { cout << 10; }} ;class Derived : public Base {...public:void mf(void) { cout << 2; }void mfstd(void) { cout << 20; }} ;Base x;Derived y;Base *px = &x;Derived *py = &y;Base *pxy = &y;px->mf();// 1, вызывается функция базового класса Basepy->mf();// 2, вызывается функция производного класса Derived;pxy->mf(); // 2, полиморфный вызов: мы не знаем, что работаем с Derived,// так как располагаем указателем на Base, но метод вызывается// из Derivedpxy->mfstd(); // 10, так как вызов не полиморфный – в базовом классе функция// не виртуальная.07.11.20113Кафедра Компьютерных методов физики: программирование, первый курс, второй семестр5.
Абстрактные классыАбстрактные классы содержат, по крайней мере, одну чистую виртуальную функцию. Впрограмме не могут быть определены объекты абстрактных классов или ссылки на них, номожно определить и использовать указатели на объекты абстрактных классов.class CPoint {public:int x,y;public:CPoint (int nx=0, int ny=0) : x(nx), y(ny) {} // конструкторCPoint (const CPoint& src) : x(src.x), y(src.y) {} // конструктор копии};class CShape { // абстрактный класс, так как в нем есть чистая функцияprotected:CPoint center; // центр объектаpublic:CShape (const CPoint &nс): center(nc) {} // конструктор// перемещение фигуры, невиртуальная функция:void MoveTo( int nx=0, int ny=0 ) { center.x = nx; center.y = ny; }// чистая функция (pure function) для подсчета площади:virtual double Square() = 0;};class CCircle : public CShape {public:int radius; // радиус кругаCCircle(int nx=0, int ny=0, int rad=0) :CShape(CPoint(nx,ny)), radius(rad) {}public:double Square() { return double(3.14159) * radius * radius; }};class CQuadrat : public CShape {public:int side; // сторона квадратаCQuadrat (int nx=0, int ny=0, int ns=0) :CShape(CPoint(nx,ny)), side(ns) {}public:double Square() { return side * side; }};CCircle c1(1,2,1), c2(2,3,8);CQuadrat q1(-2,0,3), q2(-2,0,5);CShape* shapes[4] = { &c1, &q1, &c2, &q2 };// подсчет площади всех фигур:double s = 0;for ( int i=0; i < 4; i++ ) {s += shapes[i]->Square();}6.
Множественное наследованиеМножественное наследование используется тогда, когда необходимо наделитьпроизводный класс свойствами более чем одного класса. В тех случаях, когда в базовых07.11.20114Кафедра Компьютерных методов физики: программирование, первый курс, второй семестрклассах содержатся методы с одинаковыми именами, доступ к ним из производногокласса осуществляется с помощью явного указания имени класса, членами которого ониявляются.class A {public:...void mf(void);};class B {...public:...void mf(void);};class C : public A, public B {public:...};C c;c.A::mf(); // вызывается функция класса Ac.B::mf(); // вызывается функция класса B7.
Виртуальные базовые классыДля классов, порожденных от производных классов, с общим виртуальным классом,существует только один экземпляр объекта общего базового класса.class V {...public:...void Vmf(void);};class A: virtual public V, public S {...public:...void Amf(void);};class B : virtual public V, public...public:...void Bmf(void);};T {class C : public A, public B {...public:};Класс V является единственным общим объектом внутри класса C, то есть - общим дляклассов A и B, входящих в состав класса C.07.11.20115Кафедра Компьютерных методов физики: программирование, первый курс, второй семестрОбычное наследованиеВиртуальное наследованиеCCABVAVBV8.
Пример. Наследование вектора.Унаследуем динамический массив из предыдущего задания таким образом, чтобы вэлементах базового вектора хранились рациональные числа. Размерность производноговектора при этом будем считать вдвое меньшей, по сравнению с базовым классом.class Vector;class Ratio;class ratiovector: public Vector{public://========== Конструкторы ======//// Конструктор – указываем количество пар, элементов в базовом классе// вдвое больше:ratiovector(int N=0) : Vector(N*2) {}// Конструктор копирования – не наследуется:ratiovector(const ratiovector& src) : Vector((const vector&)src) {}//============= Размерность ==========//int size() const { return Vector::size()/2; }//============= Перегрузка [] ==========//Ratio operator [] (int index){// индекс – в производном классе, в базовом – удвоение координаты для v:return Ratio(v[2*index], v[2*index+1]);}//============= Присваивание ==========//void Set(int index, const Ratio& src){v[2*index] = src.a; v[2*index+1] = src.b;}//============= Сложение ==========//ratiovector& operator+=(ratiovector& src)07.11.20116Кафедра Компьютерных методов физики: программирование, первый курс, второй семестр{if ( len != src.len ) return *this;for ( int k=0; k < src.len/2; k++ ) {int ch = v[2*k] * src.v[2*k+1] + v[2*k+1] * src.v[2*k];int zn = v[2*k+1] * src.v[2*k+1];v[2*k] = ch;v[2*k+1] = zn;}return *this;}// Деструктор - наследуется};Типовое задание 1: реализовать класс – наследник динамического массива из Задания№ 2 с переопределением его функциональности: например, производный класс вэлементах базового вектора должен хранить объекты из Задания № 1, размерностьпроизводного класса будет меньше размерности базового, оператор [ ] должен возвращатьне числа, а соответствующие объекты.Типовое задание 2: реализовать класс – наследник динамического массива из Задания№ 2 с переопределением его функциональности: например, производный класс самдолжен являться матрицей некоторой размерности.07.11.20117Кафедра Компьютерных методов физики: программирование, первый курс, второй семестр1.
ВариантБазовый класс – массив вещественных чисел, производный класс – массив вещественныхчисел, представленных в виде пар чисел x=M*10^e, где M – мантисса числа, e –экспонента (например, число 15.432=1.5432*10^(1), то есть: M=1.5432 e=1).Определите в нем конструктор, деструктор, конструктор копирования, оператор присваивания.Переопределите операции вставки, удаления элемента, а также операторы: [ ], +=, -=, *=, /=.Арифметические операторы применяются поэлементно.2. ВариантБазовый класс – массив целых чисел, производный класс – массив рациональных чиселчисел, представленных по модулю числа N (то есть в виде пар: целая часть при делении наN, остаток от деления на N).Определите в нем конструктор, деструктор, конструктор копирования, оператор присваивания.Переопределите операции вставки, удаления элемента, а также операторы: [ ], +=, -=, *=, /=.Арифметические операторы применяются поэлементно.3.