LEC_cpp3 (1119518)

Файл №1119518 LEC_cpp3 (Лекции Волковой 2009)LEC_cpp3 (1119518)2019-05-09СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла

4 лекция - C++ (3).

Единичное наследование. Производные классы.

Одним из ключевых моментов программирования в объектно-ориентированном стиле является формирование иерархических связей между пользовательскими типами путём расширения базовых классов (base) наследниками (производными классами – derived). Наследник «уточняет» определение своего базового класса путем добавления своих полей-данных и методов класса.

Конструкторы, деструкторы и operator= не наследуются!!!

Синтаксис описания производного класса следующий:

class < имя derived-cl > : < способ наследования > < имя base-cl > {...};

Способ наследования может быть public (сохраняется статус доступа для всех элементов базового класса), protected (статус доступа public-элементов базового класса понижается до protected) и private (статус доступа public и protected-элементов базового класса понижается до private).

По умолчанию структуры наследуются открытым способом (неявный public), а классы — закрытым (неявный private).

Пример:

struct A { struct B: A { class C: protected A {

int x; int z; int z;

int y; }; };

};

.........

A a; A * pa;

B b; C c, * pc = &c;

b.x = 1; pc -> z; // ошибка: доступ к закрытому полю

b.y = 2; pc -> x; // ошибка: доступ к защищённому полю

b.z = 3; pa = ( A * ) pc;

a = b; pa -> x; // правильно: поле A::x - открытое

В приведённом примере объект типа B наследует все свойства, «характерные» для типа A. С точки зрения программы объект типа B выглядит как композиция двух объектов, поэтому допустимо обобщающее побитовое присваивание a = b, при котором все поля объекта a получат значения соответствующих полей b (обратное неверно).



Ограничение видимости при наследовании откладывает отпечаток на возможности манипуляции с членами базового класса только для данного наследника и для его возможных потомков. Если указатель на объект типа C преобразовать к указателю на объект типа A, то дальнейшая работа с таким указателем будет происходить в контексте прав доступа, описанных в самом A.

Упомянутое выше обобщающее присваивание показывает, что мы можем безопасно приводить указатели на наследников к указателям на более общий тип - их базовый класс:

A a, *pa;

B b, *pb;

pb = &b;

pa = pb;

pb = ( B* ) pa;

После присвоения pa = pb мы потеряли информацию о том, что pa указывает на объекты именно типа B, поэтому уточняющее преобразование от базового класса к наследнику, вообще говоря, небезопасно во время выполнения программы. Для того чтобы быть уверенным, на объект какого именно класса ссылается указатель, необходимо использовать аппарат виртуальных функций или динамическое определение типа во время исполнения.

Перекрытие (сокрытие, замещение) имён

Производные классы могут иметь методы, замещающие или перекрывающие (overriding) методы базового класса. Если в производном классе объявлен метод, одноимённый методу базового класса (не обязательно с совпадающим профилем), то имеет место замещение метода. Из этого следуют важные выводы при работе с указателем на объект подобного класса.

struct A {

int f ( int x , int y);

int g ();

int h;

};

struct B: public A {

int x;

void f ( int x );

void h ( int x );

};

.......

A a, *pa;

B b, *pb;

pb = &b; pb -> f (1); // вызывается B::f(1)

pb -> g (); // вызывается A::g()

pb -> h = 1; // Err.! функция h(int) – не L-value выражение

pa = (A*) pb; pa -> f (1); // Err.! функция A::f(1)имеет 2 параметра

pb = &a; pb -> f (1); // Err.! расширяющее присваивание

Последняя строка является ошибочной по двум причинам: 1) уточняющее присваивание без явного преобразования типов; 2) возможна потеря данных в том случае, если B::f(int) манипулирует с полем int B::x. В этом случае память, размеченная для объекта типа A, интерпретируется как память для наследника, размер которого больше базового.

Не надо путать понятие видимости имени в некоторой области и его доступности!

Если какой-либо метод некоторого класса хочет (не беспокоясь о возможном перекрытии) вызвать другой метод, описанный в каком-либо конкретном базовом классе, то для вызова этого метода надо использовать операцию «:: » .

Аналогично и для простых функций, находящихся в некотором пространстве имен, при вызове других функций либо из другого пространства имен, либо из глобального контекста.

#include <iostream>

using namespace std;

int x;

void f (int a){cout << ":: f" << a << endl;}

class A {

int x;

public:

void f (int a){cout << "A:: f" << a << endl;}

};

class B: public A {

public:

void f (int a){cout << "B:: f" << a << endl;}

void g ();

};

void B::g() {

f(1); // вызов B::f(1)

A::f(1);

::f(1); // вызов глобальной void f(int)

//x = 2; //ошибка!!! – осущ.доступ к закрытому члену класса А

}

int main () {

B b;

b.g();

return 0;

}

Рассмотрим чуть более содержательный пример на единичное наследование в С++.

class student {

protected:

char* name;

int year;

double est;

public:

student ( char* n, int y, double e);

void print () const;

~student ();

};

class student5: public student {

protected:

char* diplom;

char* tutor;

public:

student5 ( char* n, double e, char* d, char* t);

void print () const; // эта print скрывает print из базового класса

~student5 ();

};

student5:: student5 ( char* n, double e, char* d, char* t) : student (n, 5, e) {

diplom = new char [strlen (d) + 1];

strcpy (diplom, d);

tutor = new char [strlen (t) + 1];

strcpy (tutor, t);

}

//сначала проработает конструктор student (…), а затем этот конструктор

student5 :: ~student5 () {

delete [] diplom;

delete [] tutor;

}

//сначала проработает этот деструктор, а затем деструктор ~student().

student5 :: print () const {

student :: print (); // name, year, est

cout << diplom << endl;

cout << tutor << endl:

}

Пусть есть функция f ():

void f () {

student s (“Kate”, 2, 4.18);

student5 gs (“Moris”, 3.96, “DIP”, “Nick”);

student * ps = & s;

student5 * pgs = & gs;

ps -> print(); // student :: print ();

pgs -> print(); // student5 :: print ();

ps = pgs; // base = derived – допустимо с преобразованием по

// умолчанию.

ps -> print(); // student :: print () – функция выбирается статически

// по типу указателя.

Виртуальные методы

В предыдущем пункте было указано, что наследники могут не только расширять набор методов, но и перекрывать уже определённые в базовом классе. Возникает желание использовать этот факт для разработки полиморфных алгоритмов.

Для поддержки полиморфизма на уровне языка Б. Страуструп ввёл в C++ понятие о виртуальных (с греч. «возможный») методах и связанное с ним понятие о полиморфных объектах. Механизм виртуальных методов немного похож на механизм перекрытия имён. Главное решающее отличие заключается в том, что независимо от того, к какому базовому типу приведён указатель на наследника, результат вызова виртуального метода будет зависеть от реального типа объекта, на который указывает данный указатель. То есть при вызове виртуальной функции через указатель (или ссылку) на полиморфный объект будет произведён динамический выбор тела замещённой возможной функции в зависимости от реального типа данного объекта, а не типа указателя (то есть тип полиморфного объекта отслеживается на этапе выполнения.

Синтаксис описания полиморфных типов заключается в применении префикса virtual в объявлении метода класса. При этом все наследники автоматически становятся полиморфными типами и могут описывать свои версии для виртуальных методов базовых классов (указывать virtual при описании возможной версии метода в наследниках уже необязательно).

Чтобы динамически выбирать функцию print () по типу объекта, на который ссылается указатель, переделаем наши классы т.о.:

class student {…

public:

...

virtual void print( ) const ;

};

class student5 : public student {…

public:

...

[virtual] void print( ) const ;

};

Тогда:

ps = pgs;

ps -> print(); // student5 :: print () – ф-я выбирается динамически по типу

// объекта, чей адрес в данный момент хранится в указателе

Виртуальные деструкторы

Совет: делайте деструкторы виртуальными!!!

Один из важных примеров использования аппарата виртуальных функций: вызов виртуального деструктора.

Представим, что существует алгоритм, работающий с неким типом объектов. Если программист для своих нужд уточнил этот тип, описав наследника с новыми членами, и хочет по-прежнему применять данный алгоритм без его модификации, то может возникнуть следующая ситуация. В том случае, если алгоритм производит удаление объекта, может возникнуть потеря памяти, так как алгоритм по-прежнему вызывает деструктор базового класса, и новые поля данных в наследнике не будут корректно разрушены. Техника использования виртуальных методов позволяет решить эту проблему:

Проиллюстрируем на нашем примере, пусть есть такая ф-я f():

void f () {

student * ps = new student5 (“Morris”, 3.96, “DIP”, “Nick”);

delete ps; // вызовется ~student, и не вся память зачистится

}

Но если: virtual ~student (); и

[virtual] ~student5 ();

то вызовется ~student5(), т.к. сработает динамический полиморфизм.

Итак:

  1. !Виртуальность функции, описанной с использованием служебного слова virtual не работает сама по себе, она начинает работать, когда появляется класс производный от данного с функцией с таким же профилем.

  1. Виртуальные функции выбираются по типу объекта, на который ссылается указатель (или ссылка).

  1. У виртуальных функций должны быть одинаковые профили. Исключение составляют функции с одинаковым именем и списком формальных параметров, у которых тип результата есть указатель на себя (т.е. соответственно на базовый и производный класс).

  1. Если виртуальные функции отличаются только типом результата (кроме случая выше), генерируется ошибка.

  1. Для виртуальных функций, описанных с использованием служебного слова virtual, с разными прототипами работает механизм замещения, сокрытия имен.

Абстрактные классы

Абстрактным называется класс, содержащий хотя бы одну чистую виртуальную функцию.

Чистая виртуальная функция – функция вида:

virtual <тип_рез> <имя_ф> (<список_ф_п>) = 0;

Объекты абстрактного класса создавать нельзя, а указатели на них заводить можно.

Производный от абстрактного класса может остаться абстрактным, если в нем не определены все чистые виртуальные функции базовых классов, поскольку чистые виртуальные функции наследуются и остаются виртуальными.

Пример создания и использования абстрактного класса:

class shape {

public:

virtual double area () = 0;

};

class rectangle: public shape {

double height, width;

public:

double area () {return height * width;}

};

class circle: public shape {

double radius;

public:

double area () {return 3.14 * radius * radius;}

};

Заданные описания позволяют создать массив указателей на базовый (абстрактный) класс и в одном цикле подсчитать сумму площадей разнородных геометрических фигур:

#define N 100

....

shape* p [ N ];

double total_area = 0;

Характеристики

Тип файла
Документ
Размер
91 Kb
Тип материала
Высшее учебное заведение

Тип файла документ

Документы такого типа открываются такими программами, как Microsoft Office Word на компьютерах Windows, Apple Pages на компьютерах Mac, Open Office - бесплатная альтернатива на различных платформах, в том числе Linux. Наиболее простым и современным решением будут Google документы, так как открываются онлайн без скачивания прямо в браузере на любой платформе. Существуют российские качественные аналоги, например от Яндекса.

Будьте внимательны на мобильных устройствах, так как там используются упрощённый функционал даже в официальном приложении от Microsoft, поэтому для просмотра скачивайте PDF-версию. А если нужно редактировать файл, то используйте оригинальный файл.

Файлы такого типа обычно разбиты на страницы, а текст может быть форматированным (жирный, курсив, выбор шрифта, таблицы и т.п.), а также в него можно добавлять изображения. Формат идеально подходит для рефератов, докладов и РПЗ курсовых проектов, которые необходимо распечатать. Кстати перед печатью также сохраняйте файл в PDF, так как принтер может начудить со шрифтами.

Список файлов лекций

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6358
Авторов
на СтудИзбе
311
Средний доход
с одного платного файла
Обучение Подробнее