Skip to the content.

Наследование - это механизм, позволяющий создавать производные (дочерние) классы на основе уже существующих (родительских).

struct Person // родительский класс
{
  // Геттеры
  string name() const {return name_;}
  int age() const {return age_;}

private:
    string name_;
    int age_;
};

struct Student : Person // дочерний класс
{
    string university() const {return uni_;}
private:
    string uni_;
};

У дочернего класса можно вызывать публичные методы родительского класса:

Student s;
std::cout << s.name() << " " << s.age() << " " << s.university() << std::endl;

Поля добавленные в дочернем классе инициализируются в конструкторе дочернего класса, а те поля, которые унаследованны от родительского класса инициализируются внутри конструктора родительского класса. При создании объекта произвольного класса сначала вызывается конструктор родительского класса, если у родительского класса нет конструктора по умолчанию, но есть конструктор с параметрами, то его нужно вызывать самостоятельно (если есть конструктор по умолчанию, то он вызовется сам):

struct Person
{
  Person(string name, int age) : name(name), age(age)
  {}
  ...
};

struct Student : Person 
{
  Student(string name, int age, string uni) : Person(name, age), uni_(uni)
  {}
  ...
};

Аналогично работает деструктор: при удалении экземпляра Student, вначале вызовется деструктор Person. Это делается автоматически и на это никак нельзя повлиять.

Для дочерних классов определены следующие приведения:

Student s("Alex", 21, "Oxford");

// ссылка на Student -> ссылка на базовый класс
Person & l = s; // Student & приводится к Person &

// указатель на Student -> указатель на базовый класс
Person * r = &s; // Student * приводится к Person *

В обратную сторону такие приведения не работают!

Благодаря приведению ссылок, мы можем инициализировать родительский класс при помощи дочернего. При этом копируются только поля родительского класса (такое поведение называется - срезка):

Student s("Alex", 21, "Oxford");
Person p = s; // Person("Alex", 21);

Будет вызван только конструктор копирования Person(Person const& p);, который ничего не знает про uni_.

Protected

Если в родительском классе поля/методы были объявлены с модификатором private, то внутри дочернего класса невозможно будет к ним обратиться.

Если нам потребуется определить поля/методы так, что бы наследники к ним имели доступ, а внешний код нет, то нужно использовать модификатор protected:

struct Person
{
protected:
    string name_;
    int age_;
};

struct Student : Person
{
    // у Student есть доступ к полям name_ и age_
};

Синтаксис наследования

В общем случае синтаксис наследования выглядит так:

struct Child : <modifier> Parent {};

где modifier это одно из ключевых слов: public, protected, private.

Если не указать модификатор, то будет использован модификатор по умолчанию, для структур это public, для классов - private. При этом совершенно не важно является ли Parent классом или структурой, все зависит от дочернего Child.