Что такое наследование в c++

Наследование

Наследование является одной из главных особенностей объектно-ориентированного программи­рования. В С++ наследование поддерживается за счет того, что одному классу разрешается при своем объявлении включать в себя другой класс. Наследование позволяет построить иерархию классов от более общего к более частным. Этот процесс включает в себя определение базового класса, определяющего общие качества всех объектов, которые будут выведены затем из базового класса. Базовый класс представляет собой наиболее общее описание. Выведенные из базового класса классы обычно называют производными классами. Производные классы включают в себя все черты базового класса и, кроме того, добавляют новые качества, характерные именно для данного про­изводного класса. Чтобы продемонстрировать, как работает этот процесс, в следующем примере созданы классы, классифицирующие различные типы средств передвижения.
В качестве начального рассмотрим класс, названный road_vehicle (дорожное средство передви­жения), который служит очень широким определением средств передвижения по дорогам. Он хранит информацию о числе колес движущегося средства и о числе пассажиров, которые он может вмещать:

class road_vehicle <
int wheels;
int passengers;
public:
void set_wheels(int num);
int get_wheels();
void set_pass(int num);
int get_pass();
>;

Теперь можно использовать это определение дорожного средства передвижения для того, что­бы определить конкретные типы. Например, в следующем фрагменте кода определен класс truck (грузовик), используя класс road_vehicle:

class truck: public road_vehicle <
int cargo;
public:
void set_cargo(int size);
int get_cargo();
void show();
>;

Обратим внимание, каким образом наследуется класс road_vehicle. Общая форма записи насле­дования имеет следующий вид

class имя_нового_класса: доступ наследуемый_класс <
//тело нового класса
>

Здесь использование доступ факультативно, но если оно используется, то должно принимать значение public или private. Пока же все наследуемые классы будут использовать спецификатор public. Он означает, что все члены класса-предшественника, имеющие спецификатор доступа public, сохраняют тот же спецификатор досту­па во всех производных классах. Поэтому в данном примере члены класса truck имеют доступ к функциям-членам класса road_vehicle так, как если бы эти функции-члены были объявлены внут­ри класса truck. Однако функции-члены класса truck не имеют доступа к частным членам класса road_vehicle.

Следующая программа иллюстрирует наследование с помощью создания двух подклассов клас­са road_vehicle: truck и automobile:

#include
class road_vehicle <
int wheels;
int passengers;
public:
void set_wheels(int num);
int get_wheels ();
void set_pass(int num);
int get_pass ();
>;
class truck: public road_vehicle <
int cargo;
public:
void set_cargo(int size);
int get_cargo();
void show ();
>;
enum type ;
class automobile: public road_vehicle <
enum type car_type;
public:
void set_type (enum type t);
enum type get_type();
void show();
>;
void road_vehicle::set_wheels(int num)
<
wheels = num;
>
int road_vehicle::get_wheels()
<
return wheels;
>
void road_vehicle::set_pass(int num)
<
passengers = num;
>
int road_vehicle::get_pass()
<
return passengers;
>
void truck::set_cargo(int num)
<
cargo = num;
>
int truck::get_cargo ()
<
return cargo;
>
void truck::show ()
<
cout

www.c-cpp.ru

Создание базового класса

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

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

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

В этом примере мы написали программу, которая создает объект класса student , сохраняя в нем его имя, фамилию, отчество и список оценок.

Нужно создать еще один класс, в котором будут храниться данные преподавателей. Дадим ему название — teacher . Как вы уже поняли, мы не будем описывать все методы этого класса с нуля, а просто унаследуем его от класса human . Тогда, не нужно будет реализовывать хранение имени, фамилии и отчества препода. Это уже есть в базовом классе human .

У класса teacher появилось новое свойство — количество учебных часов, отведенное преподавателю на единицу времени (семестр). Весь остальной функционал наследуется от базового класса human . Если бы мы писали все с нуля, то одинакового кода бы получилось в разы больше, и его поддержка усложнилась бы на порядок.

Если сборка программы прошла без ошибок, то результат работы программы будет таким:

В класс human можно добавить еще больше свойств, которые будут описывать данные, имеющиеся у любого человека. Например, номер паспорта, дату рождения, прописку и место проживания.

code-live.ru

Что такое наследование в c++

Видно, что он объект класса Derived содержит внутри себя объект класса Base . Для того, чтобы создать объект Derived , нужно сначала создать Base .

new Derived(); // отвести место в памяти под объект Derived и вызвать его конструктор

Рассмотрим реализацию конструкторов классов Base и Derived (далее по тексту определение некоторых конструкторов и деструкторов, а также методов классов написаны внутри определений классов исключительно для удобства, реально их нужно писать в .cpp-файлах):
После этого в результате выполнения строчки будет выведено В скомпилированном коде внутри конструктора Derived будет вызван конструктор Base .

Таким образом, важно запомнить следующие вещи:
1) При создании объекта класса-наследника вызывается конструктор наследуемого им класса
2) Код конструктора базового класса вставляется в начало конструктора суперкласса.

Отсутствие конструктора по умолчанию у базового класса

Предположим, что в классе Base нет конструктора по умолчанию − например, класс определен следующим образом: В таком случае код не скомпилируется.

Можно явно указать, какой конструктор вызывать в Derived у Base: Здесь будет вызван конструктор Base с параметром 42.
Еще один пример: перед конструктором Derived компилятор попробует вызывать конструктор Base по умолчанию (несмотря на то, что вызывать конструктор Base с параметром param кажется весьма естественным), что повлечет за собой ошибку компиляции.

Кроме того, передаваемые конструктору суперкласса параметры можно использовать для вызова конструктором базовых классов:

Продолжение примера с переводчиком

2. Права доступа при наследовании

Описание модификаторов прав доступа

private-члены доступны лишь внутри своих классов, и в наследниках недоступны.
В языке C++ доступны три типа модификаторов прав доступа к элементам класса (полям, методам, конструкторам и деструктору):
, и всегда, когда доступны private, доступны protected и public, и всегда, когда доступны protected, доступны public.

Право доступа protected означает «разрешить доступ мне и всем моим наследникам (а также их наследникам и т.д.)».

Возвращаясь к примеру с переводчиком

Права доступа для виртуальных методов

Рассмотрим классы Translator и TranslatorFrRu: Далее в коде в месте вызова метода translate для t компилятором будут проверены права доступа для класса Translator, потому что t объявлена в виде Translator *t .

Поэтому в месте неминуемо должно быть написано «public», иначе код не скомпилируется.
В скомпилированном коде на языке C++ прав доступа нет.
Поэтому в месте может быть любой модификатор.

Но для того, чтобы предупредить нежелательное пользование классами вроде следующего: разумно поставить на место private.

Примечание Например, в языке Java код компилируется в байт-код, исполняемый Java-машиной, и там права доступа проверяются в момент исполнения кода. Поэтому в случае с языком Java на месте должно было стоять слово public. Исторически язык C++ был создан как один из быстро работающих языков, а всякое лишнее действие во время исполнения влечет за собой некоторую потерю эффективности, поэтому в момент работы программы никаких проверок прав доступа не происходит.

3. Закрытое (private) наследование

Различия между закрытым (private) и открытым (public) наследованием

На место можно поставить одно из слов private , public , а также ничего не поставить.

Рассмотрим случай, когда сюда поставили private вместо public . Напомним, что раньше можно было писать так: , поскольку класс Derived − наследник класса Base. Но теперь этот код перестанет компилироваться с ошибкой «объект типа Derived не принадлежит Base», а код с ошибкой «метод foo класса Derived − private».

Пример применения

Пример Предположим, что нам нужно реализовать стек на базе массива ( std::vector ) или списка ( std::list ). Рассмотрим следующую реализацию: , а также такую: Никаких содержательных различий между этими двумя способами нет. Приведенный выше пример − почти единственный пример применения private-наследования. Поэтому почти никакого смысла в private-наследовании нет.

Случай, когда вместо не указано ничего, эквивалентен указанию там private.

1. struct и class

В языке C++ struct − почти синоним слова class.

В аккуратно написанном коде вида разницы между таким классом и структурой нет. Различие между словами class и struct лишь в том, что для элементов класса, для которых не указаны права доступа, по умолчанию используются права private, а для структуры − public.

То же касается и модификаторов наследования: С точки зрения компилятора разницы между class и struct нет. С психологической точки зрения struct представляет собой некую маленькую структуру, а class − большой объект, поэтому struct обычно не наследуют (хотя это возможно).

Пример использования struct:

2. О перечисляемом типе enum

Решение №0 (define-ы)

Таким образом, мы назначаем каждому языку соответствующее число, и при каждом появлении в коде слова «ENGLISH» препроцессор заменит его на 0.

У такого решения есть следующие минусы:

  • во всех файлах исходного кода, где подключен .h-файл с подобными define-ами нельзя использовать слова ENGLISH, FRENCH и т. д. Например, до включения подобного .h-файла следующий код компилировался, а после − нет: После же включения этого заголовочного файла мы получим множественные ошибки компиляции.

Решение №1 (константы)

Мы можем определить следующие константы: Так нельзя писать в хедере (из-за возможных ошибок линковки, когда два .cpp-файла используют данный хедер, эти константы скомпилируются в объектные модули каждого из этих файлов, а далее произойдет ошибка линковки).

Поэтому в хедере нужно писать объявление констант (объявление переменных, вообще говоря, пишется аналогично): У такого решения тоже есть минусы:

  • Оно противоречит интуитивному восприятию человека (язык − не число!)
  • Поскольку язык − число, некоторые программисты будут в качестве значения передавать число 0
  • При правке (добавлении новых языков, например, возможны следующие ошибки): Впоследствии эту ошибку будет довольно сложно выявить
  • Так же, как и в предыдущем варианте, возможны конфликты имен (но это решается помещением кода в пространство имен)
  • Решение №2 (enum)

    Мы определили перечисляемый тип Language.

    Примечание В последней строчке может как стоять запятая, так и не стоять.

    Использование определенного типа Language: Видно, что перечисляемый тип загромождает пространство имен своими константами, но обычно он помещается внутрь класса или namespace’a, например: Тогда обращаться к нему, а также его элементам придется так:

    О связи между перечисляемым типом и int

    Вообще говоря, перечисляемый тип представляет из себя int (целое число), но во избежание ошибок явно присваивать переменной перечисляемого типа целое значения запрещено (третья строчка). Но с помощью явного приведения типов это возможно (последняя строчка), так мы показываем компилятору, что понимает, что делаем и снимаем с него ответственность за дальнейшее.

    Кроме того, первый элемент перечисляемого типа будет храниться в памяти как число «0», второй − как «1» и т.д.

    www.amse.ru

    Функция get_average_score вычисляет среднее арифметическое всех оценок студента. Все публичные свойства и методы класса human будут доступны в классе student .

    Конструктор базового класса

    Список оценок студента хранится в векторе.

    Создание объекта класса student

    После инициализации объекта, происходит вывод полного имени студента с помощью функции get_full_name . Эта функция была унаследована от базового класса human .

    Затем программа вычислияет средний балл студента и выводит его на экран. Этим занимается функция get_average_score , которую мы описали внутри класса student .

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

    Создайте файл teacher.h :

    Также, мы можем создать класс, который будет описывыть студента заочной формы обучения. Его мы унаследовали бы от класса student , добавив какие-либо дополнительные данные.

    Наследование классов в C++ — урок 13

    Создайте файл human.h :

    Наследование от базового класса

    Теперь создайте новый класс student , который будет наследником класса human . Поместите его в файл student.h .

    Реализуем пользовательский интерфейс для работы с классом student .

    Создание класса-наследника teacher

    Создание объекта класса teacher

    Изменим содержимое файла main.cpp , чтобы проверить работу класса teacher .

    Можно таким же образом создать класс, в котором будут храниться данные обслуживающего персонала или руководящего состава. Наследование используют, когда у каждой группы объектов есть общие параметры, но для каждой из этих групп нужно хранить более кастомные данные.

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

    Когда нужно использовать конструктор

    Если у класса много свойств — их совсем не обязательно задавать в конструкторе. Для сохранения отдельных свойств класса используют set-функции. Например, для сохранения номера паспорта, можно создать публичный метод set_passport_number(std::string number) , который будет принимать значение свойства и сохранять его в объекте, через переменную this .

Популярное:

  • Приказ об аттестационной комиссии в колледже Приказ об аттестационной комиссии в колледже МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИХабаровского края от 20 октября 2014 года N 60 О создании аттестационной комиссии для проведения аттестации педагогических работников в целях установления […]
  • Госпошлина за удостоверение по аттестации Как уплачивается госпошлина за аттестацию в Ростехнадзоре Если ваша деятельность связана с опасным оборудованием и от лиц (работников предприятия) зависит промышленная безопасность, вам придется воспользоваться услугами […]
  • Опека и попечительство гражданское право шпаргалка Гражданское право, Гатин А.М., 2009 Гражданское право, Гатин А.М., 2009. Предлагаемое учебное пособие составлено в соответствии с требованиями и программой Государственного образовательного стандарта, утвержденного Министерством […]
  • Можно ли оформить доверенность на ипотеку Доверенность на продажу квартиры: виды и способы оформления Доверенность на продажу недвижимости представляет собой документ, в котором собственник (доверитель) передаёт свои полномочия на продажу недвижимости третьему (доверенному) […]
  • Расчитать стаж он Калькулятор подсчета страхового стажа Сегодня 24 июля 2018 г., 19:44 Посчитать стаж работы для больничного листа поможет онлайн калькулятор. Пособие по временной нетрудоспособности, а также пособие по беременности и родам рассчитывается […]
  • Правила оформления решения Решение – это правовой акт, принимаемый коллегиальными и совещательными органами учреждений, организаций, предприятий в целях разрешения наиболее важных вопросов их деятельности. 1 Решениями называются также совместные распорядительные […]
  • Когда пишется мягкий знак после шипящих правило Азбучные истины Интерактивный диктант Учебник ГРАМОТЫ: пунктуация Имена и названия. Интерактивный тренажер Полезные ссылки Летнее чтение Запоминалки Цитаты о языке Скороговорки Пословицы и поговорки Учебник ГРАМОТЫ: орфография Выберите […]
  • При стаже вождения более 3 лет Стаж вождения Телефонная консультация 8 800 505-92-65 229 ответов от юристов и адвокатов Первый раз сталкнулся с такой историей (стаж вождения - 15 лет). Я инвалид 1-й гр. не имею физической возможности на инв. коляске преодалевать […]