17.6 – Добавление функционала в производный класс

Добавлено 31 июля 2021 в 17:19

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

Во-первых, давайте начнем с простого базового класса:

#include <iostream>
 
class Base
{
protected:
    int m_value;
 
public:
    Base(int value)
        : m_value(value)
    {
    }
 
    void identify() { std::cout << "I am a Base\n"; }
};

Теперь давайте создадим производный класс, унаследованный от Base. Поскольку мы хотим, чтобы производный класс мог устанавливать значение m_value при создании экземпляров производных объектов, мы заставим конструктор Derived вызывать конструктор Base в списке инициализации.

class Derived: public Base
{
public:
    Derived(int value)
        : Base(value)
    {
    }
};

Добавление нового функционала в производный класс

В приведенном выше примере, поскольку у нас есть доступ к исходному коду класса Base, мы можем добавить функциональность непосредственно в Base, если захотим.

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

Кроме того, могут быть случаи, когда даже невозможно изменить базовый класс. Рассмотрим код из стандартной библиотеки. Мы не можем изменять код, являющийся частью стандартной библиотеки. Но мы можем наследоваться от этих классов, а затем добавлять наш собственный функционал в наши производные классы. То же самое касается сторонних библиотек, где вам предоставляются заголовки, но код поставляется предварительно скомпилированным.

В любом случае лучший ответ – создать собственный класс и добавить необходимый функционал в этот производный класс.

Одно очевидное упущение в классе Base – это способ открытого доступа к m_value. Мы могли бы исправить это, добавив функцию доступа в базовый класс, но для примера мы собираемся добавить ее в производный класс. Поскольку m_value была объявлена защищенной в базовом классе, Derived имеет к ней прямой доступ.

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

class Derived: public Base
{
public:
    Derived(int value)
        :Base(value)
    {
    }
 
    int getValue() { return m_value; }
};

Теперь внешний код, чтобы получить доступ к значению m_value, сможет вызвать getValue() для объекта типа Derived.

int main()
{
    Derived derived(5);
    std::cout << "derived has value " << derived.getValue() << '\n';
 
    return 0;
}

Этот код дает следующий результат:

derived has value 5

Хотя это должно быть очевидно, объекты типа Base не имеют доступа к функции getValue() в Derived. Следующий код не работает:

int main()
{
    Base base(5);
    std::cout << "base has value " << base.getValue() << '\n';
 
    return 0;
}

Это потому, что в Base нет функции getValue(). Функция getValue() принадлежит Derived. Поскольку Derived является Base, он имеет доступ к собственности Base. Однако у Base нет доступа ни к чему в Derived.

Теги

C++ / CppLearnCppДля начинающихКласс (программирование)НаследованиеОбучениеОбъектно-ориентированное программирование (ООП)Программирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.