При построении иерархии классов нередки случаи, когда базовая функцианальность должна быть изменена/дополнена. Например код предыдущей секции:
class Base {
public:
void hi() { cout << "Hi, I'm base class" << endl; }
};
class Derived : public Base {
public:
void hi() { cout << "Hi, I'm derived class" << endl; }
};
// ...
Derived d;
Base b = d;
d.hi(); // "Hi, I'm derived class"
b.hi(); // "Hi, I'm base class"
Наша из экземпляра наследника вызвать переопределенную функцию. Достигается это посредством определения виртуальных функций (virtual functions).
По умолчанию объектная модель C++ работает с невиртуальными функциями.
Чтобы сделать функцию виртуальной необходимо добавить ключевое слово virtual и она станет виратульной для всех наследниках на всех уровнях.
Для перегружаемой функции можно явно указать, что она является виртуально функцией и сама переопределяет виртаульную функцию. Тем не менее это ключевое слово является необязательным. Приведенный пример ниже будет работать из без указания override
class Base {
public:
virtual void hi() { cout << "Hi, I'm base class" << endl; }
};
class Derived : public Base {
public:
void hi() override { cout << "Hi, I'm derived class" << endl; }
};
// ...
Derived d;
Base& b = d; // нужна именно ссылка
d.hi(); // "Hi, I'm derived class"
b.hi(); // "Hi, I'm derived class"
Помимо случаев, когда нужно переопределить функциональность, есть масса примеров, когда необходимо работать с конрактом объекта (то есть с декларацией, что объект может делать, но не описывающий как). Для таких случаях в C++ есть чистые виртуальные функции. Класс в котором виртуальный метод описывается впервые, должен определять его тело либо декларировать метод как не имеющую собственной реализации чистую виртуальную функцию, путем добавления =0
к описанию функции:
virtual void foo() = 0;
Класс, который определяет или наследует хотя бы одну чистую виртуальную функцию, является абстрактным. Экземпляры абстрактных классов создать нельзя. Абстрактный класс может реализовываться только как подобъект производного, неабстрактного класса.
#include <iostream>
using namespace std;
class A {
public:
virtual string name() = 0;
};
class B: public A {
public:
string name() {return "B";}
};
class C: public A {
public:
string name() {return "C";}
};
void hi(A& a) {
cout << "Hi " << a.name() << "!" << endl;
}
int main()
{
B b;
C c;
hi(b);
hi(c);
return 0;
}