Принятый ответ очень хороший, и тот, который я рекомендую, когда это возможно.К сожалению, такой уровень абстракции трудоемок в реализации и не решает всей проблемы.
- Вы должны религиозно использовать pimpl idiom , чтобы сохранить все типы WinAPIиз заголовочных файлов уровня абстракции.Заголовки Windows должны быть включены только в файлы реализации (
.cpp
), а не в заголовки. - На практике вам приходится создавать множество собственных классов, которые по существу захватываютта же информация, что и базовый тип WinAPI (например, LOGFONT), потому что клиент интерфейса абстракции должен передать и получить ее.В конечном итоге вам понадобится много стандартного кода для преобразования между типами уровня абстракции и типами WinAPI.
- Большой рефакторинг, необходимый для введения уровня абстракции, может быть большой работой в унаследованной кодовой базе, особенно если этокод используется многими проектами.
Реализация уровня абстракции требует включения заголовков окон.Предположим, что один из независимых от платформы типов, введенных вами для включения уровня абстракции, имеет метод, называемый GetFont
.Независимый от платформы код, который опирается на него, увидит GetFont
, потому что в этом блоке перевода не будет упоминания <windows.h>
.Но файл реализации (файл .cpp
), который реализует уровень абстракции в Windows, будет конфликтовать с макросом препроцессора GetFont
, поскольку он должен включать <windows.h>
.Таким образом, использование pimpl ограничивает масштаб проблемы, но не решает ее полностью.
То, что я начал делать, как в более новом коде, который использует хорошие уровни абстракции, так и в более старом коде, который не был хорошО предотвращении утечек в платформу имен для конкретных платформ является создание оболочек для заголовков WinAPI.Я заменяю все строки #include <windows.h>
в коде, которым я управляю, на #include "apiwrappers/windows.h"
, который является ссылкой на файл, который выглядит примерно так:
// Prevents Windows headers from defining macros called min and max, which
// conflict with identifiers in the C++ standard library.
#ifndef NOMINMAX
#define NOMINMAX
#endif
// Distinguishes between different types of handles so that we get better
// error checking at compile time.
#ifndef STRICT
#define STRICT
#endif
#include <windows.h> // the "real" <windows.h>
// Lowercase far and near are perfectly reasonable names for local variables
// and parameters, so we don't want redefinitions of them.
#undef far
#undef near
// But lots of other Win32 headers use FAR and NEAR, which are typically
// defined to far and near. We need them to be empty.
#ifdef FAR
#undef FAR
#define FAR
#endif
#ifdef NEAR
#undef NEAR
#define NEAR
#endif
// Windows defines macros to select between the "ANSI" and "wide" versions
// of many API functions (e.g., GetMessage macro expands to GetMessageA or
// GetMessageW). We undefine many of these here to avoid naming collisions.
// Call the specific -W functions explicitly instead of relying on these
// macros.
#undef GetFont
#undef GetMessage
// ...
Я увеличиваю список #undef
S, как я разрешаю столкновения.У меня нет исчерпывающего предложения.
Для других заголовков WinAPI я делаю нечто подобное, но с остальными они гораздо проще.