Абстракные классы , виртуальные функции

Сложные для понимания технологии хорошо усваиваются на реальных примерах.

фотка 1

Если хочешь понять как что-то работает сделай это что-то сам.

С абстрактнами классами или виртуальными функциями надо сначала понять когда их удобно использовать.

Так вот момент истины наступает когда ваш проект начинает разрастаться вширь и вглубь...

Ну например вы подключили к своему проекту какое-то оборудование. Настроили управление им.

Потом решили подключить другое оборудование и поняли , что оно как и предыдущее оборудование управляется однотипно, то есть как бы можно создать набор функций (интерфейс) и через них управлять однотипно обоими вариантами оборудования.

Вот тут и надо создать сначала абстрактный класс, в нем прописать наш набор функций с типом virtual и унаследовать оба наших оборудования от этого абстрактного класса.

В класса унаследованных от абстрактного класса надо конечно реализовать эти функции применительно к каждому  конкретному оборудованию.

В чем тут выгода? В том что теперь можно работать с каждым из вариантов оборудования единообразно через вызовы фунций из набора в абстрактном классе.

А вызываться на самом деле будет функция конкретного класса (оборудования).

Но и это еще не все.

Допустим у вас есть абстрактный класс A (уровень 0), далее имеем унаследованный от него класс A1 (1 уровень).

Далее предположим , что класс A1 уже многократно используется в вашем коде и менять его уже очень не хочется. Так сказать он самодостаточен и логичен.

И есть предположим в классе A1 некая функция A1::foo, в которой вы сохраняете куда-то какие-то данные.

Но вот вам еще захотелось добавить некий дополнительный контроль сохраняемых данных.

Чтобы не менять класс A1 можно просто объявить функцию foo виртуальной .

Далее унаследоваться от класса A1, то есть создать класс A2 (уровень 2) , где создать новую реализацию функции foo, в которой сделать сначала проверку записываемых данных , а потом вызвать функцию A1::func.

Таким образом вы не меняете реализацию класса A1. И получаете класс A2 расширяюший функциональность класса A1.

В коде вы продолжаете многократно использовать класс A1 и по необходимости добавляете где-надо использование класса A2.

И так далее ....

В итоге у вас получается грамотная иерархическая единственно правильная схема разделения функциональности и наследования классов.