Ohrangos.ru

Юридический журнал

Классы и наследование в c++

Классы и наследование в 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
  • При правке (добавлении новых языков, например, возможны следующие ошибки): Впоследствии эту ошибку будет довольно сложно выявить
  • Так же, как и в предыдущем варианте, возможны конфликты имен (но это решается помещением кода в пространство имен)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Доступно про наследование в С++

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

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

С этим классом должно быть все понятно. Его объекты будут характеризоваться одним параметром » health » (здоровье) и есть один метод, позволяющий вывести значение этого параметра на экран. Можно создавать фермеров:

На экран выведется Unit health: 10 и Unit health: 30. Ничего нового пока.

Теперь создадим воинов. Кроме того, что у них есть здоровье, как у фермеров, они могут наносить урон ( damage ). Можно было бы создать отдельный класс для воинов с параметрами health и damage , но гораздо проще создать класс воинов, имеющий параметр health класса фермеров и свой параметр damage . Это и есть наследование:

То есть теперь, создавая объект класса Soldier , можно использовать как его поля, так и поля базового класса Unit :

В результате у Геракла теперь 10 healthи 30 damage, а у Ахиллеса 40 healthи 50 damage. Сейчас я поясню несколько моментов, которые могли вызвать затруднения, но сначала необходимо изменить метод доступа поля health класса Unitс privateна protected, чтобы код скомпилировался. protectedотличается отprivateтем, что protectedне запрещает доступ к полям классам-наследникам.

Теперь о моментах:
-при объявлении класса-наследника необходимо представить базовый класс:
class Soldier : public Unit
-при объявлении базового класса необходимо предоставить модификатор доступа (public, private, protected) перед именем базового класса. Модификаторpublic позволяет классу-наследнику наследовать поля базового класса так, как они объявлены в базовом классе, protectedпреобразует public в protected, а модификатор privateнаследует поля базового класса, как private, вне зависимости от того, как они заданы в базовом классе. Следует отметить, что наследование ни как не изменяет базовый класс
-в представленном наследнике, для примера, введено несколько конструкторов. При создании объекта класса Soldier, в случае первых двух конструкторов для инициализации полей базового класса Unitбудет использоваться его конструктор по умолчанию. Третий же конструктор Soldier вызывает конструктор с параметром базового Unit

Хорошо, теперь аналогичным образом создадим лошадей, которые в отличии от фермеров, будут двигаться, т.е. будут иметь параметр speed:

Все лошади будут иметь 10 healthи 20 speed.

А теперь создадим всадников, которые будут иметь характеристики как фермеров(здоровье) и солдат (damage), так и лошадей (speed):

И все бы ничего, но наследуя и Horseи Soldier, Horsemanнаследует 2 копии Unit. Решить эту проблему можно использовав ключевое слово virtualперед объявлениями о наследовании класса Unit(не путайте с виртуальными функциями):

Все, класс всадников создан! При создании объекта класса Horsemanбудут использоваться конструкторы по умолчанию базовых классов.

Допустим, что солдат тоже может двигаться (имеет параметр speed):

Неоднозначность можно решить дважды использовав оператор разрешения контекста:

Но правильнее было бы переназначить поле в классе Horseman (код целиком):

Если Вам понравилась статья, проголосуйте за нее

Голосов: 0 Голосовать

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Самая актуальная документация по Visual Studio 2017: Документация по Visual Studio 2017.

В этом разделе рассматривается использование производных классов для создания расширяемых программ.

Новые классы могут наследоваться от существующих классов с помощью механизма «наследования» (см. сведения начиная с раздела Одиночное наследование). Классы, используемые для наследования, называются «базовыми классами» определенного производного класса. Производный класс объявляется с помощью следующего синтаксиса:

После тега (имени) класса следует двоеточие и список базовых спецификаций. Названные таким образом базовые классы, вероятно, были объявлены ранее. Базовые спецификации могут содержать описатель доступа, представляющий собой одно из ключевых слов: public, protected или private . Эти описатели доступа отображаются перед именем базового класса и применяются только к базовому классу. Эти описатели контролируют разрешение производного класса на использование членов базового класса. Сведения о доступе к членам базового класса см. в разделе Контроль доступа к членам. Если описатель доступа пропущен, доступ к базе считается private . Базовые спецификации могут содержать ключевое слово virtual, указывающее на виртуальное наследование. Это ключевое слово может отображаться до или после описателя доступа, если таковые имеются. Если используется виртуальное наследование, базовый класс называется виртуальным базовым классом. Дополнительные сведения см. в разделе Виртуальные базовые классы.

Можно определить несколько базовых классов, разделив их запятыми. Если определен один базовый класс, модель наследования называется Одиночное наследование. Если определено несколько базовых классов, модель наследования называется Множественное наследование.

Классы. Фигуры. Наследование

Создан абстрактный класс Point — ось в трёхмерном пространстве с начальной точкой и высотой.
Производный от него Параллелепипед — принимает два параметра (координаты Х У) для установки противоположной начальной точкой вершиной.
Производный от Параллелепипеда — Тетраэдр — принимает ещё два параметра (координаты Х У третьего угла).

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

Другие публикации  Колония поселение домашнее проживание
Все права защищены; 2019 Ohrangos.ru