Итоговый тест№11.
Наследование в языке C++.
Теория
Наследование позволяет моделировать отношения типа «является» между двумя объектами. Объект, который наследует, называется дочерним классом. Объект, которого наследуют, называется родительским классом.
При наследовании дочерний класс наследует все члены родительского класса.
При инициализации объектов дочернего класса, сначала выполняется построение родительской части объекта, а затем уже дочерней части объекта. Рассмотрим детально:
Сначала выделяется память для объекта дочернего класса (достаточная порция для двух частей, из которых состоит объект: родительская и дочерняя).
Вызывается соответствующий конструктор дочернего класса.
Выполняется построение родительской части с использованием соответствующего конструктора родительского класса. Если конструктор не указан, то используется конструктор по умолчанию родительского класса.
Список инициализации дочернего класса инициализирует члены дочернего класса.
Выполняется тело конструктора дочернего класса.
Управление возвращается обратно в caller.
Освобождение памяти (уничтожение) происходит в порядке, противоположном построению: от дочерних до родительских классов.
Язык C++ имеет 3 спецификатора доступа: public, private и protected. Спецификатор protected используется для разрешения доступа к членам дружественным классам/функциям и дочерним классам, всем остальным объектам — доступ закрыт.
Есть 3 типа наследования: public, private и protected. Наиболее распространенный тип наследования — public.
Таблица спецификаторов доступа и типов наследования:
Спецификатор доступа в родительском классе |
Спецификатор доступа при наследовании типа public в дочернем классе |
Спецификатор доступа при наследовании типа private в дочернем классе |
Спецификатор доступа при наследовании типа protected в дочернем классе |
public |
public |
private |
protected |
private |
Недоступен |
Недоступен |
Недоступен |
protected |
protected |
private |
protected |
Дочерние классы могут изменять методы родительского класса, добавлять свой функционал, изменять спецификатор доступа наследуемых членов или даже скрывать методы родительского класса. Всё это выполняется в теле дочернего класса.
Множественное наследование позволяет дочернему классу иметь сразу несколько родительских классов. Не рекомендуется использовать множественное наследование, если есть альтернативные решения.
Задание №1
Для каждой из следующих программ определите результат выполнения. Дайте его объяснение. Если программа не скомпилируется, то объясните почему. Запускать код не нужно, вы должны определить результат/ошибки программ без помощи компилятора.
a)
include <iostream>
class Parent {
public:
Parent () {
std::cout << "Parent()\n";
}
~Parent () {
std::cout << "~Parent()\n";
}
};
class Child: public Parent{
public:
Child () {
std::cout << "Child()\n";
}
~Child () {
std::cout << "~Child()\n";
}
};
int main () {
Child ch;
}
b)
#include <iostream>
class Parent{
public:
Parent (){
std::cout << "Parent()\n";
}
~Parent () {
std::cout << "~Parent()\n";
}
};
class Child: public Parent {
public:
Child () {
std::cout << "Child()\n";
}
~Child () {
std::cout << "~Child()\n";
}
};
int main () {
Child ch;
Parent p;
}
c) #include <iostream>
class Parent {
private:
int m_x;
public:
Parent (int x): m_x(x) {
std::cout << "Parent()\n";
}
~Parent () {
std::cout << "~Parent()\n";
}
void print () {std::cout << "Parent: " << m_x << '\n'; }
};
class Child: public Parent{
public:
Child (int y): Parent (y) {
std::cout << "Child()\n";
}
~Child () {
std::cout << "~Child()\n";
}
void print () { std::cout << "Child: " << m_x << '\n'; }
};
int main () {
Child ch (7);
ch.print ();
}
d)
#include <iostream>
class Parent {
protected:
int m_x;
public:
Parent (int x): m_x(x) {
std::cout << "Parent()\n";
}
~Parent () {
std::cout << "~Parent()\n";
}
void print() { std::cout << "Parent: " << m_x << '\n'; }
};
class Child: public Parent
{
public:
Child (int y): Parent(y) {
std::cout << "Child()\n";
}
~Child () {
std::cout << "~Child()\n";
}
void print () { std::cout << "Child: " << m_x << '\n'; }
};
int main () {
Child ch(7);
ch.print();
}
e)
#include <iostream>
class Parent {
protected:
int m_x;
public:
Parent (int x): m_x(x) {
std::cout << "Parent()\n";
}
~Parent () {
std::cout << "~Parent()\n";
}
void print () {std::cout << "Parent: " << m_x << '\n'; }
};
class Child: public Parent {
public:
Child (int y): Parent(y)
{
std::cout << "Child()\n";
}
~Child () {
std::cout << "~Child()\n";
}
void print () { std::cout << "Child: " << m_x << '\n'; }
};
class D2: public Child {
public:
D2(int z): Child(z) {
std::cout << "D2()\n";
}
~D2() {
std::cout << "~D2()\n";
}
// Обратите внимание, здесь нет метода print()
};
int main (){
D2 d (7);
d.print ();
}
Задание №2
a)
Создайте классы Apple и Banana, которые наследуют класс Fruit. У класса Fruit есть две переменные-члены: name и color.
Следующий код:
int main() {
Apple a("red");
Banana b;
std::cout << "My " << a.getName() << " is " << a.getColor() << ".\n";
std::cout << "My " << b.getName() << " is " << b.getColor() << ".\n";
return 0;
}
Должен выдавать следующий результат:
My apple is red.
My banana is yellow.
b)
Добавьте новый класс GrannySmith, который наследует класс Apple.
Следующий код:
int main () {
Apple a("red");
Banana b;
GrannySmith c;
std::cout << "My " << a.getName() << " is " << a.getColor() << ".\n";
std::cout << "My " << b.getName() << " is " << b.getColor() << ".\n";
std::cout << "My " << c.getName() << " is " << c.getColor() << ".\n";
return 0;
}
Должен выдавать следующий результат:
My apple is red.
My banana is yellow.
My Granny Smith apple is green.
