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

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

Одной из отличительных особенностей языка C++ является множественное наследование, при таком наследовании класс наследник может получить поля и методы от 2-х и более классов родителей.

Рассмотрим на примере:
Пусть у нас будут базовые классы студент и работник и класс наследник работающий студент.


class Student
{ 
public:
    Student ()
    {
       this->Name="Ivan";
       this->course=1;
    }
    void getInfoSt(){cout<Name<< " "<course <<" course"<<endl;}

  string Name;
  unsigned int course; //указатель на переменную в динамической памяти
};

class Employer
{
public:
    Employer ()
    {
       this->position="manager";
    }
    void getInfoEmp(){cout<position<<endl;}

  string position;
};


class WorkingStudent : public Student, public  Employer
{
public:
    void getInfoWS()
    {
        cout<Name<<", "<course <<" course"<<" also working as "<position<<endl;
    }
};

В main напишем код:

WorkingStudent c_WS;
c_WS.getInfoWS();

В результате в консоль выведется «Ivan, 1 course also working as manager»

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

//Методы классов-родителей
c_WS.getInfoSt();
c_WS.getInfoEmp();

Как это произошло:
Т.к. класс работающего студента мы наследуем от 2-х классов студент и работник, то вызываются конструкторы (в данном случае по умолчанию) для этих классов:

  • сначала для работающего студента
  • потом для студента, т.к. он стоит первым в записи class WorkingStudent : public Student…
  • последним для работника

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

Далее мы можем использовать эти поля и методы в классе наследнике, а также вызывать методы базовых классов у объектов класса WorkingStudent.

При уничтожении (выходе из зоны видимости) класса WorkingStudent вызываются деструкторы в порядке, обратном конструкторам:

  • сначала для работника
  • потом для студента
  • самым последним вызывается деструктор класса-наследника WorkingStudent

Почему такой порядок – как говорилось ранее – функции и классы вызываются с инкрементом адресов и удаляются с декрементом – следовательно «вверху» памяти будет базовый класс, потом первый предок и потом следующие предки.
Т.е.
child();
parent1();
parent2();
//code
~parent2();
~parent1();
~child();

Вызываемые функции ставятся «ниже» кода класса, и по мере выполнения удаляются из стека, пока не дойдут до деструктора, после удаления деструктора открывается следующий класс и тд.

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

Множественное наследование, вызов одинаковых методов:
В предыдущем примере мы использовали различные имена методов, но что делать, если мы хотим использовать одинаковое имя?
изменим имена методов getInfoSt, getInfoEmp на getInfo

А в main напишем код:

//Методы классов-родителей
((Student)c_WS).getInfo();
((Employer)c_WS).getInfo();

В этом случае мы делаем приведение к типу класс «студент» или «работник» и у них вызываем требуемый метод.

 

Вызов конструкторов базовых классов, отличных от конструкторов по умолчанию:
Если требуется вызвать конструктор базовых классов, отличный от конструкторов по умолчанию, то можно сделать конструктор класса-наследника Child так:

Child(arg1, arg2) : Parent1(arg1), Parent2(arg2)
{

}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *