Если вы сделаете функцию виртуальной внутри базового класса, все, что происходит от нее, также будет иметь виртуальную функцию.
Будучи виртуальным, если вы создадите экземпляр A
, он все равно будет вызывать A::f
.
Если вы создаете экземпляр B и сохраняете его в указателе типа A*
. И тогда вы позвоните A*::->f
, тогда он позвонит B
B::f
.
Что касается побочных эффектов, то, вероятно, не будет никаких побочных эффектов, кроме небольшой (незаметной) потери производительности.
Существует также очень небольшой побочный эффект, может существовать класс C, который также является производным от A, и он может реализовывать C::f
и ожидать, что если вызывается A*::->f
, то он ожидает, что A::f
называться. Но это не очень распространено.
Но, скорее всего, если существует C
, то он вообще не реализует C::f
, и в этом случае все в порядке.
Будьте осторожны, если вы используете уже скомпилированную библиотеку и изменяете ее заголовочные файлы, то, что вы ожидаете, вероятно, не сработает. Вам нужно будет перекомпилировать заголовок и исходные файлы.
Чтобы избежать побочных эффектов, вы можете сделать следующее:
- Создайте тип
A2
, производный от A
, и сделайте его f
виртуальным.
- Используйте указатели типа
A2
вместо A
- Производное
B
от типа A2
.
- Таким образом, все, что использовало А, будет работать таким же образом, гарантировано
В зависимости от того, что вам нужно, вы также можете использовать has-a
отношение вместо is-a
.