Каждый уважающий себя программист должен уметь работать с языками программирования, которые относятся к Си-семейству. Это – современный подход при написании разнообразного контента. В основном упор делается на C++. Профессиональные разработчики способны применять данную «лексику» как для элементарных, так и для крупных запутанных задач.

Каждый язык имеет собственные нюансы, алгоритмы, объекты и функции. Немаловажным моментом является так называемое наследование. Зная, что это такое, можно с легкостью составить довольно сложный программный код с минимальными усилиями. В статье будут рассмотрены принципы наследования в C++ и C#.

Основная терминология

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

  1. Базовый класс – некий класс, который выступает «базисом» при наследовании производным классом.
  2. Деструкторы – методы класса, необходимые для деинициализации объекта.
  3. Идентификатор – уникальное имя, присваиваемое функциям, переменным, иным объектам программирования.
  4. Инкапсуляция – механизмы, связывающие коды (операции) с информацией, коими происходит манипуляция. Осуществляется дополнительная защита от внешнего вмешательства и неправильного задействования.
  5. Класс – шаблоны, определяющие тот или иной объект в программе, его форму.
  6. Конструкторы – методы классов. Используются для инициализации элементов.
  7. Массивы – коллекции переменных одного и того же вида. К ним обращение происходит при помощи общих имен.
  8. Переменная – основная единица при составлении машинного кода. Элемент памяти, которому присвоили имя и значение.
  9. Полиморфизм – свойство классов решать похожие задачи разными способами. Одно имя используется сразу для нескольких методов, обладающих похожими друг на друга назначениями.
  10. Производный класс – своеобразный класс, наследующий от базового.
  11. Рекурсия – операция, при которой функция вызывает сама себя.
  12. Строка (String name) – последовательность символов (с именем), заключенная в двойные кавычки.
  13. Структура – образец, определяющий форму объекта. От класса отличается тем, что все его составляющие являются открытыми изначально.
  14. Указатели – маркеры/объекты, хранящие в себе адреса памяти.
  15. Функции – подпрограмма или операция, которая используется при решении тех или иных задач.

Все это обязательно поможет каждому программисту. Предложенная терминология используется не только в Си-семействе, но и в остальных programming languages.

О классах C++

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

Немаловажный раздел – это классы и объекты. Они тесно связаны с так называемым наследованием, на котором будет заострено внимание далее.

Классом принято в C++ называть абстракции, которые описывают методы и свойства элементов, которых не существует. Объекты здесь – это конкретизированное представление абстракций со своими методами и свойствами.

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

  1. Инкапсуляцией. С ее помощью происходит объединение в классах данных и методов. Детализация скрывается от юзера.
  2. Полиморфизмом. Свойство, посредством которого объекты классов с одними и теми же интерфейсами без сведений о типе и внутренней структуре могут задействоваться при необходимости.
  3. Наследованием. Процесс, который позволяет создавать классы-потомки. За основу берется уже существующий вариант, а характеристики «родителя» присваиваются «следующему поколению».

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

  1. Private – методы и свойства, которые объявлены внутри class, будут доступны только в пределах оного.
  2. Public – доступ предоставляется иным составляющим и функциям приложения.
  3. Protected – предоставляет доступ к членам класса, а также к дружественным и дочерним «составляющим». За пределами тела class доступ закрывается.

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

Наследование Си Плюс-Плюс

В Си Плюс-Плюс наследование производится между классами. Тип отношений – «является». Class, от которого осуществляется рассматриваемая «операция», называется базовым (суперклассом или родительским). Тот элемент, который «забирает» свойства и характеристики – дочерним (подклассом или производным).

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

Класс «Человек»

Вот код, который поможет представить в приложении человека:

class Human
{
public:
    std::string m_name;
    int m_age;
 
    Human(std::string name = "", int age = 0)
        : m_name(name), m_age(age)
    {
    }
 
    std::string getName() const { return m_name; }
    int getAge() const { return m_age; }
 
};

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

Пример предусматривает спецификатор public. Отсюда следует, что имеющиеся переменные и методы открытые. Но можно сделать их «приватными», как это обычно бывает. Данный прием позволяет контролировать доступ и следить за наследованием.

Внимание: программерам в процессе работы с рассматриваемым действием может потребоваться работа с include iostream. Это – элемент стандартной библиотеки в Си Плюс-Плюс, который представлен заголовочным файлом с классами, переменными и функциями.

Public Class «Игроки в баскетбол»

На основании предложенного выше кода будем работать с наследованием в Си Плюс-Плюс. Требуется написать утилиту, отслеживающую сведения о тех, кто играет в баскетбол. Сохраняется средний уровень игры, а также то, сколько очков набрал конкретный человек:

Все о наследовании в Си-семействе

Это – незавершенный public class. Дополнительно необходимо знать имя и возраст игрока. Для этого используется первый представленный код. Вывести запрашиваемую информацию предлагается несколькими способами:

  1. Добавить в «Баскетбольные игроки» новые члены с соответствующими материалами. Не самый лучший выход, так как он приводит к дублированию кода.
  2. При помощи так называемой композиции добавить public Human в виде члена класса BasketballPlayer. Но это некорректное решение.
  3. Произвести настройку кода так, чтобы новый «элемент кода» наследовал те или иные атрибуты от первого. Это и есть тип отношений «является».

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

Сделать «Баскетбольных игроков» дочерним

Для реализации поставленной задачи требуется после public class BasketballPlayer воспользоваться двоеточием. Здесь без ключевого слова public не обойтись, как и без имени классового элемента. Это – открытая операция:

Все о наследовании в Си-семействе

Также программисты часто думают, что такое так называемое множественное наследование. Этот вопрос будет рассмотрен позже.

Вследствие проделанных манипуляций происходит «заимствование» информации от родительских классов. У «Игроков в баскетбол» имеются и собственные члены – m_points и m_gameAverage. В них есть необходимость, так как на экран выводятся не только сведения об именах и возрасте.

Полный код утилиты будет выглядеть так:

Все о наследовании в Си-семействе

В итоге на экране появится надпись «Антон» (на английском).

Public элемент Employer

Пусть будет еще один «потомок» от Human. За основу возьмем информацию о работниках. Подчиненный – это человек. Соответственно, изучаемый процесс здесь уместен:

Все о наследовании в Си-семействе

Сразу прописывать public в самом начале кодификации не нужно. Это нарушает структуру кода. «Сотрудник» забирает от «Человека» два метода – имя и возраст, а также обладает собственными переменными и одним методом. PrintNameAndWage() задействует переменные как из родительского «источника», так и из собственного.

Внимание: BasketballPlayer и Employer не связаны, но написаны в пределах одной и той же программы. Кодификация имеет следующий вид:

Все о наследовании в Си-семействе

В итоге на экране появится надпись «Иван: 350».

Цепочки

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

Все о наследовании в Си-семействе

Информация берется из public Employer, который когда-то получал сведения из Human.

«Заимствование» и C#

Перед тем, как задумываться, что такое так называемое множественное наследование в Си-семействе, требуется разобраться с «обычным». Теперь рассмотрим несколько примеров C#.

Принципы использования здесь будут примерно такими же, как и в уже рассмотренном варианте. Для создания «дочерних» элементов не требуется никаких особых навыков и знаний. Для того, чтобы было проще работать с кодом, будем использовать тип public. Это поможет избежать появления дополнительных окон и сообщений об ошибке при получении доступа к запрашиваемым сведениям.

Важно учитывать, что:

  1. C# предусматривает одиночное «заимствование». От двух и более public (или иных) классовых составляющих процесс производиться не может.
  2. Отношение наследования – некоторое отношение, демонстрирующее переход от общей абстракции к конкретной.
  3. Абстрактный классовых «объект» — классовая составляющая, объекты которого нельзя создавать. Ключевое слово new здесь не используется. Элемент задействуется в качестве прародителя.
  4. Sealed – слово, которое позволяет устанавливать запрет на наследников. Пример — string. Права «заимствования» здесь не имеют места.
  5. Virtual – превращает метод в виртуальный, чтобы использовать предопределение наследников.

Все это поможет в дальнейших примерах. Пока рано задумываться, что такое часто применяемое множественное наследование, потому как не все разбираются в обычном. Ниже будет наглядный пример «манипуляции» в C#.

Пример «Животные» и конструкторы

Пусть будет классовый элемент Animal. В нем будут создаваться поля и методы, характерные для всей «живности»:

  • вес;
  • сколько живет (в среднем);
  • наличие хвоста;
  • что ест.

От него сделаем дочернюю классовую составляющую (тоже public) – «Собака». Исходный код:

Все о наследовании в Си-семействе

Стоит обратить внимание на то, что «заимствованию» в Шарпе не подлежат так называемые конструкторы. Если они есть у родителей, то у наследников доступа к оным не будет. Несмотря на это, вызов будет осуществляться автоматически. Это – дефолтный конструктор. Чтобы его вызвать, рекомендуется использовать ключевик base.

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

Все о наследовании в Си-семействе

Внимание: запись public virtual делает информацию виртуальной.

Множественное наследование в C

До сих пор рассматривалось лишь «заимствование», которое предусматривало одиночный вариант. Дочерний классовый элемент в таком случае предусматривает только одного родителя (для удобства используется тип public). Но Си-семейство предусматривает и множественный «подход».

В С++

Множественный «метод» — это когда у дочернего классового «объекта» будет несколько предков. Пример – отслеживание работы преподавателей. Работать будем с предыдущими элементами кода. Учитель – это человек, но также он будет подчиненным.

Задумываясь, что такое в Си-семействе множественное наследование, стоит обращать внимание на логические связи. Без них освоить рассматриваемое направление невозможно. Поэтому создадим новый классовый «объект» под названием «Учитель».

Чтобы реализовать подход, потребуется:

  • присвоить переменным (int main или другим) для удобства «тип» public;
  • прописать «стандартную» запись «заимствования»;
  • через запятую указать тип «заимствования», а также второго родителя.

В конечном итоге получится такой код:

Все о наследовании в Си-семействе

В предложенном примере используется «заимствование» типа public.

Возможные неурядицы

Несмотря на то, что рассмотренный прием – это довольно быстрое и простое расширение «базисного», его применение на практике способно привести в определенным ошибкам. Сложность утилит увеличивается. Поддержка кода способна стать настоящей проблемой.

Рассмотрим несколько наиболее распространенных ситуаций:

1.Возникновение неоднозначности. Такие ситуации возникают, когда у нескольких родителей имеются методы с одинаковыми именами. Здесь при компилировании «c54G…» просматривает наличие метода getID() у «Wireless…», который отсутствует. В итоге компилятор продвинется вверх по цепи, отыщет у родительских классовых элементов соответствующий «объект». Он обнаружен у USB и Network. В результате появится сообщение об ошибке, так как компилятор не поймет, какой именно ID использовать.

Все о наследовании в Си-семействе

Для исправления ситуации достаточно внести уточнение:

Все о наследовании в Си-семействе

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

Все о наследовании в Си-семействе

Во втором случае сканеры и принтеры служат устройствами. Питаются от розетки и получают свойства «Powered…». Но ксерокс объединяет эти два девайса. Поддержка такого кода способна привести не только в медленной работе утилиты, но и к непредвиденным поворотам.

В C#

Также стоит выяснить, что такое упомянутое ранее множественное наследование, но уже в Си Шарп. Работать, как и в прошлых случаях, будем с public, несмотря на то, что обычно переменные и другие составляющие бывают private.

Об интерфейсах

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

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

  • конструкторы;
  • константы;
  • поля;
  • статистические составляющие.

Объявляется и используется по следующему примеру:

Все о наследовании в Си-семействе

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

Все о наследовании в Си-семействе

Интерфейсы необходимы для множественного «заимствования».

О непосредственном «перенятии»

Множественное наследование в C – это процесс перенятия классовой составляющей сразу от двух родителей. В Шарпе данный вариант используется редко, так как ему на смену пришли интерфейсы. Здесь классовая составляющая способна реализовывать сразу несколько interfaces. Несмотря на это, «идентификатор» public в Sharp применяется, и весьма часто.

При реализации нескольких интерфейсов используется разделительный символ «запятая». Кодификация окажется следующей:

Все о наследовании в Си-семействе

Тут:

  1. Интерфейсом объявлен некий IDrawable. Это – метод рисования некоторого числа объектов.
  2. Может реализовывать Image.
  3. Circle и Image – разные сущности без базового class. Для устранения неполадок создается указатель на «главный» public интерфейс.

Так, в Шарпе для «перенятия» множественного типа задействованы или abstract classes, или интерфейсы.

Все о наследовании в Си-семействе
Все о наследовании в Си-семействе

Также вам может быть интересен курс «Программист C» в Otus.