Я не думаю, что перегрузки виртуальных функций обрабатываются иначе, чем перегрузки обычных функций. Хотя может быть один побочный эффект.
Предположим, у нас есть иерархия из 3 слоев:
struct Base {};
struct Derived: Base { void foo(int i); };
struct Top: Derived { void foo(int i); }; // hides Derived::foo
Когда я пишу:
void bar(Derived& d) { d.foo(3); }
вызов статически разрешается до Derived::foo
, независимо от того, какой истинный (во время выполнения) тип имеет d
.
Однако, если я тогда введу virtual void foo(int i);
в Base
, тогда все изменится. Внезапно Derived::foo
и Top::foo
становятся переопределениями вместо простой перегрузки, которая скрывает имя в соответствующем базовом классе.
Это означает, что d.foo(3);
теперь разрешается статически не напрямую к вызову метода, а к виртуальной диспетчеризации.
Поэтому Top top; bar(top)
будет вызывать Top::foo
(через виртуальную диспетчеризацию), где ранее он вызывал Derived::foo
.
Это может быть нежелательно. Это может быть исправлено путем явной квалификации вызова d.Derived::foo(3);
, но это, несомненно, является нежелательным побочным эффектом.
Конечно, это в первую очередь проблема дизайна. Это произойдет только в том случае, если подпись совместима, иначе у нас будет скрыто имя и не будет переопределения; поэтому можно утверждать, что наличие «потенциальных» переопределений для не виртуальных функций в любом случае вызывает проблемы (не знаю, существует ли для этого какое-либо предупреждение, оно может быть оправдано, чтобы не попасть в такую ситуацию).
Примечание: если мы удалим Top, тогда будет совершенно нормально представить новый виртуальный метод, поскольку все старые вызовы уже были обработаны Derived :: foo в любом случае, и, следовательно, может быть затронут только новый код
Об этом следует помнить при внедрении новых методов virtual
в базовом классе, особенно когда неизвестный код неизвестен (библиотеки доставляются клиентам).
Обратите внимание, что C ++ 0x имеет атрибут override
для проверки того, что метод действительно переопределяет базовый виртуальный; хотя это не решает насущную проблему, в будущем мы можем представить, что компиляторы будут предупреждать о «случайных» переопределениях (то есть переопределениях, не отмеченных как таковые), и в этом случае такая проблема может быть обнаружена во время компиляции после Внедрение виртуального метода.