Наследование
Как говорилось во введении в c++ в классах можно выполнять наследование, т.е. передавать все или часть свойств класса родителя классу наследнику и дополнять их.
Общий вид наследования выглядит так:
class имя_нового_класса: модификатор_доступа наследуемый_класс
{
//тело нового класса
}
Модификаторы доступа при наследовании мы уже рассматривали в теме «модификаторы доступа»
Продемонстрируем на примере:
//Создадим класс Person
class Person
{
public:
Person()
{
this->Name="Vasya";
this->age= new unsigned int (20); //создание переменной в динамической памяти
}
~Person()
{
delete age; //удаление переменной в динамической памяти
}
void getInfo()
{
cout<<"Name: "<< this->Name <<" age "<< *(this->age) <<endl; //выводим данные на экран
}
protected:
string Name;
unsigned int * age; //указатель на переменную в динамической памяти
};
И унаследуем от него класс student (студент – это человек, который учится на каком-то курсе, поэтому добавим ему поле курс и метод getInfoStudent())
class student : public Person
{
public:
student(uint course)
{
this->course=course;
}
void getInfoStudent()const
{
cout<<"Name: "<< this->Name <<" age "<< *(this->age) <<" studing at "<course<<" course"<<endl; //выводим данные на экран
}
uint course;
};
Теперь в функции main мы можем вызвать:
cout<<"c_Person created"<<endl;
Person c_Person;
c_Person.getInfo();
cout<<endl<<endl;
cout<<"c_Student created"<<endl;
student c_Student(2);
c_Student.getInfo();
c_Student.getInfoStudent();
Здесь мы создали объект класса Person и у него доступен только 1 метод getInfo(), после мы создали объект класса student и у него доступны как метод базового класса getInfo(), так и метод getInfoStudent(), в этом методе выводится номер курса
Отдельно стоит отметить модификатор доступа protected: в базовом классе – за счет него и модификатора при наследовании public мы имеем доступ к полям Name и age базового класса (что к слову может нести некоторый риск, например при работе с указателем age, для защиты, используем ключевое слово const).
Немного оговоримся про организацию памяти и вызовы конструкторов и деструкторов:
Для создания класса наследника (student) мы должны сначала создать класс родитель т.к. нам нужны его поля и лишь потом вызвать класс наследник
При уничтожении (вызове деструктора) сначала вызывается деструктор класса наследника, потом класса родителя.
Так как в этом примере данные в классе-наследнике хранятся на стеке – отдельно создавать деструктор нет необходимости (подойдет и по умолчанию).
Переменная по указателю age удалится в деструкторе базового класса.
К слову о наследовании –нам ничто не мешает от класса student или Person унаследовать еще класс/классы.
И главный момент – зачем это нужно?
- отсутствие дублирования кода-нам не нужно заново переписывать функции во всех классах-наследниках
- более четкое выделение структуры и методов работы с классами (логика наследования)
- у наследования есть еще одна особенность – указатель на базовый класс является указателем и на классы наследники:
Что это значит – мы можем создать функцию, принимающую в качестве аргумента базовый класс, а «подсунуть» ему класс наследник.
Особенно ярко это будет видно в следующей теме про виртуальные методы.