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

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

Листинг 13.23. Наследование

#include <iostream>

class A {          // Базовый класс
public:
   void func1() { std::cout << "A::func1()" << std::endl; }
};
class B: public A { // Класс B наследует класс A
public:
   void func2() { std::cout << "B::func2()" << std::endl; }
};
class C: public B { // Класс C наследует классы A и B
public:
   void func3() { std::cout << "C::func3()" << std::endl; }
};

int main() {
   C c;             // Создаем экземпляр класса C
   c.func1();       // A::func1()
   c.func2();       // B::func2()
   c.func3();       // C::func3()
   return 0;
}

В этом примере вначале класс B наследует все члены класса A. Затем объявляется класс C, который наследует все члены и класса B, и класса A. Каждый класс добавляет один новый метод. Таким образом, экземпляр класса C имеет доступ ко всем методам классов A и B. Класс A называется базовым классом или суперклассом, а класс B — производным классом или подклассом. В то же время класс B является базовым для класса C. При наследовании используется следующий формат объявления класса:

class <Производный класс>: [<Модификатор доступа>] <Базовый класс> {
   <Объявления членов класса>
} [<Объявления переменных через запятую>];

В параметре <Модификатор доступа> можно указать следующие модификаторы:

  • public — открытое наследование. Все общедоступные и защищенные члены базового класса становятся соответственно общедоступными и защищенными членами производного класса;
  • private — закрытое наследование. Все общедоступные и защищенные члены базового класса становятся закрытыми членами производного класса;
  • protected — защищенное наследование. Все общедоступные и защищенные члены базового класса становятся защищенными членами производного класса.
Обратите внимание

При использовании закрытого наследования можно изменить уровень доступа некоторых общедоступных и защищенных членов базового класса. Сделать это можно с помощью инструкции using:

using <Базовый класс>::<Член класса>;

Объявление следует добавить в соответствующий раздел в объявлении производного класса. Пример изменения уровня доступа отдельных членов класса при закрытом наследовании приведен в листинге 13.24.

Листинг 13.24. Изменение уровня доступа при закрытом наследовании

#include <iostream>

class A {
public:
   void func1() { std::cout << "A::func1()" << std::endl; }
   void func2() { std::cout << "A::func2()" << std::endl; }
};
class B: private A {       // Закрытое наследование
public:
   using A::func2;         // Открываем доступ к func2()
   void func3() { func1(); }
};

int main() {
   B obj;
   // obj.func1(); // Ошибка. Метод func1() - закрытый член класса!
   obj.func2();    // A::func2()
   obj.func3();    // A::func1(). Вызов метода func1() из B::func3()
   return 0;
}

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

<Название производного класса>(<Параметры>)
                     : <Название базового класса>(<Значения>)
{
   // Тело конструктора
}

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

Листинг 13.25. Порядок вызова конструкторов и деструкторов

#include <iostream>

class A {
public:
   int x;
   A(int a) : x(a) {                  // Конструктор
      std::cout << "A::A()" << std::endl;
   }
   ~A() { std::cout << "A::~A()" << std::endl; }
};
class B: public A {
public:
   int y;
   B(int a, int b) : A(b), y(a) {     // Конструктор
      std::cout << "B::B()" << std::endl;
   }
   ~B() { std::cout << "B::~B()" << std::endl; }
};
class C: public B {
public:
   int z;
   C(int a, int b, int c)
       : B(b, c), z(a) {              // Конструктор
      std::cout << "C::C()" << std::endl;
   }
   ~C() { std::cout << "C::~C()" << std::endl; }
};

int main() {
   C obj(10, 20, 30);
   std::cout << "A::x = " << obj.x << " B::y = " << obj.y
             << " C::z = " << obj.z << std::endl;
   return 0;
}

Результат выполнения программы:

A::A()
B::B()
C::C()
A::x = 30 B::y = 20 C::z = 10
C::~C()
B::~B()
A::~A()

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов