Слово virtual задаёт виртуальную функцию - метод класса, который возможно изменить в классах наследниках. То как будет выполняться метод определится в период исполнения программного кода.
Следовательно, разработчику нет необходимости иметь представление о конкретном типе объекта для работы над ним с помощью виртуальных функций. Хватает информации, что объект, в заявленной функции, относится к некоторому классу или классу наследнику.
Виртуальный метод может быть не реализован вовсе. Класс с таким методом называется абстрактным. Объекты такого класса создавать нельзя. Но можно создавать объекты наследников этого класса.
Для наглядности можно разобрать следующую модель программы.
Определим классы как указано ниже:
1 2 3 4 5 6 7 8 9 10 11 |
class Food // класс еда { public: virtual char n() {return 1;} }; class Fruit : public Food // класс фрукт { public: char n() {return 2;} }; |
Далее выполним такой код:
1 2 3 4 5 6 7 8 |
Fruit f1; Food f2; Food &a = f1; // объявляем еду, которая на самом деле фрукт Food &b = f2; // объявляем не фруктовую еду f1.n(); // вызываем метод класса Fruit a.n(); // вызываем метод класса Food, но будет вызван метод класса Fruit b.n(); // вызываем метод класса Food |
Чтобы вызвать метод любого класса с помощью указателя или ссылки, нам необходимы виртуальные функции.
Прописано основное слово virtual до функции n класса Fruit. Данное слово определяет что функция - виртуальная. Следовательно, вызывая a.n(), мы вызовем метод класса Fruit, хоть ссылка направлена на класс Food, потому что a - на самом деле фрукт. А вот b.n() вызовет метод класса Food.
Похожая ситуация наблюдается с указателями
1 2 3 4 5 6 7 8 |
Fruit f; Food *p = &f; p -> n(); //Вызывается Fruit::n() Food x; p = &x; p -> n(); //Вызывается Food::n() |
Если метод какого-то класса метод сделали виртуальным, то во всех последующих классах этот метод также останется виртуальным, независимо от наличия слова virtual в них.