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

Бывают ошибки, в которых, в общем-то, никто не виноват, но они от этого не перестают быть ошибками. Представьте, что давным-давно (в Visual Studio 6.0) был разработан проект, в котором присутствует класс CSampleApp, являющийся наследником от CWinApp.

В базовом классе есть виртуальная функция WinHelp. Наследник перекрывает эту функцию и выполняет необходимые действия. Визуально это представлено на рисунке 1.

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

Рисунок 1 — Работоспособный корректный код, который создан в Visual Studio 6.0

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

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

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

Рисунок 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. Анализатор предупредит об опасных виртуальных функциях диагностическим сообщением V301.

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

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

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

Правообладателем курса "Уроки разработки 64-битных приложений на языке Си/Си++" является ООО "Системы программной верификации". Компания занимается разработкой программного обеспечения в области анализа исходного кода программ. Сайт компании: http://www.viva64.com.

Мой блог находят по следующим фразам

Данная статья "Урок 12. Паттерн 4. Виртуальные функции" размещена на сайте Компьютерные сети и многоуровневая архитектура интернета (conlex.kz) в ознакомительных целях.

Уточнения, корректировки и обсуждения статьи "Урок 12. Паттерн 4. Виртуальные функции" - под данным текстом, в комментариях.

Ответственность, за все изменения, внесённые в систему по советам данной статьи, Вы берёте на себя.

Копирование статьи "Урок 12. Паттерн 4. Виртуальные функции", без указания ссылки на сайт первоисточника Компьютерные сети и многоуровневая архитектура интернета (conlex.kz), строго запрещено.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *