﻿# Урок 12\. Паттерн 4\. Виртуальные функции

Бывают ошибки, в которых, в общем\-то, никто не виноват, но они от этого не перестают быть ошибками\. Представьте, что давным\-давно \(в Visual Studio 6\.0\) был разработан проект, в котором присутствует класс CSampleApp, являющийся наследником от CWinApp\. В базовом классе есть виртуальная функция WinHelp\. Наследник перекрывает эту функцию и выполняет необходимые действия\. Визуально это представлено на рисунке 1\.

![12_Pattern_04_Virtual_functions_ru/image2.png](https://import.viva64.com/docx/blog/12_Pattern_04_Virtual_functions_ru/image2.png)

_Рисунок 1 \- Работоспособный корректный код, который создан в Visual Studio 6\.0_

Затем проект переносится на Visual Studio 2005, где прототип функции WinHelp изменился, но этого никто не замечает, так как в 32\-битном режиме типы DWORD и DWORD\_PTR совпадают и программа продолжает корректно работать \(рисунок 2\)\.

![12_Pattern_04_Virtual_functions_ru/image4.png](https://import.viva64.com/docx/blog/12_Pattern_04_Virtual_functions_ru/image4.png)

_Рисунок 2 \- Не корректный, но работоспособный 32\-битный код_

Ошибка ждет, чтобы проявить себя в 64\-битной системе, где размер типов DWORD и DWORD\_PTR различен \(рисунок 3\)\. Получается, что в 64\-битном режиме классы содержат две РАЗНЫЕ функции WinHelp, что естественно некорректно\. Учтите, что подобные ловушки могут скрываться не только в MFC, где часть функций изменили типы своих аргументов, но и в коде ваших приложений и сторонних библиотек\.

![12_Pattern_04_Virtual_functions_ru/image6.png](https://import.viva64.com/docx/blog/12_Pattern_04_Virtual_functions_ru/image6.png)

_Рисунок 3 \- Ошибка проявляет себя в 64\-битном коде_

Рассмотрим данную ошибку на реальном примере\. Есть прекрасная библиотека компонентов BCGControlBar\. Наверняка вы про нее слышали, поскольку компоненты компании BCGSoft Ltd включены в Microsoft Visual Studio 2008 Feature Pack\. Так вот, если скачать ознакомительную версию этой библиотеки, установить ее и выполнить поиск слова "WinHelp" по \.h\-файлам\.\.\. то мы увидим, что везде, где якобы перекрыта эта функция, используется параметр DWORD, вместо DWORD\_PTR\. А это означает, что справка в 64\-битной системе в этих классах будет вести себя некорректно\.

Почему подобная ошибка может до сих пор быть в коде такой известной библиотеки? Мы думаем, дело в том, что клиентам компании доступны исходные коды этой библиотеки и клиенты всегда могут поправить эти коды\. Кроме того, в настоящее время функция WinHelp используется очень редко\. Намного чаще используется HtmlHelp\. А она\-то в BCGControlBar имеет правильный параметр DWORD\_PTR\. Однако факт остается фактом\. Ошибка есть в реальном коде и компилятор ее не обнаружит\. Причем такие ошибки могут оставаться не выявленными годами\.

_Примечание\. Статья писалась в октябре 2009 года, и, скорее всего, в следующих версиях эта ошибка будет исправлена, тем более что мы сообщили о ней разработчикам библиотеки\._

## Диагностика

Ошибки, связанные с виртуальными функциями в 64\-битном коде, могут быть обнаружены статическим анализатором [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/)\. Анализатор предупредит об опасных виртуальных функциях диагностическим сообщением [V301](https://pvs-studio.ru/ru/docs/warnings/v301/)\.

Виртуальная функция считается опасной, если:

1. Функция объявлена в базовом классе и в классе\-потомке\.
1. Типы аргументов функций не совпадают, но эквивалентны на 32\-битной системе \(например: unsigned, size\_t\) и не эквивалентны на 64\-битной\.

_Авторы курса: Андрей Карпов \([karpov@viva64\.com](mailto:karpov@viva64.com)\), Евгений Рыжков \([evg@viva64\.com](mailto:evg@viva64.com)\)\._

_Правообладателем курса "Уроки разработки 64\-битных приложений на языке Си/Си\+\+" является ООО "Системы программной верификации"\. Компания занимается разработкой программного обеспечения в области анализа исходного кода программ\. [Сайт компании](https://pvs-studio.ru/ru/pvs-studio/)\._