Ответ 1
Существует больше способов решить эту проблему - у каждого есть свои плюсы и минусы.
1.) Используйте макросы #ifdef, #endif
// Note: not sure if "WINDOWS" or "WIN32" or something else is defined on Windows
#ifdef WINDOWS
#include <window.h>
#else
// etc.
#endif
class MyClass
{
public:
// Public interface...
private:
#ifdef WINDOWS
HWND m_myHandle;
#else
// etc.
#endif
};
Плюсы:
- Максимальная скорость программы.
Минусы:
- Худшая читаемость. На многих платформах это может стать очень грязным.
- Включая специфику платформы, может сломать что-то. windows.h определяет много макросов с нормальными именами.
2.) Как уже было написано, вы можете использовать полиморфизм:
// IMyClass.h for user of your class:
class IMyClass
{
public:
virtual ~IMyClass() {}
virtual void doSomething() = 0;
};
// MyClassWindows.h is implementation for one platform
#include <windows.h>
#include "IMyClass.h"
class MyClassWindows : public IMyClass
{
public:
MyClassWindows();
virtual void doSomething();
private:
HWND m_myHandle;
};
// MyClassWindows.cpp implements methods for MyClassWindows
Плюсы:
- Многое, гораздо более чистый код.
Минусы:
- Пользователь не может создавать экземпляры вашего класса напрямую (особенно не в стеке).
- Вы должны предоставить специальную функцию для создания: например, объявить IMyClass * createMyClass(); и определить его в MyClassWindows.cpp и других определенных для платформы файлах. В этом случае (ну, на самом деле, во всем этом случае полиморфизма) вы также должны определить функцию, которая уничтожает экземпляры - чтобы сохранить идиому "кто бы ее не создал, должен также уничтожить".
- Небольшое замедление из-за виртуальных методов (в наши дни практически совершенно незначительные, кроме очень, очень особых случаев).
- Примечание. Распределение может быть проблемой на платформах с ограниченной памятью из-за проблем с фрагментацией ОЗУ. В этом случае его можно решить, используя какой-то пул памяти для ваших объектов.
3). Идиома PIMPL.
// MyClass.h
class MyClass
{
public:
MyClass();
void doSomething();
private:
struct MyClassImplementation;
MyClassImplementation *m_impl;
}
// MyClassWindows.h
#include <windows.h>
#include "MyClass.h"
struct MyClassImplementation
{
HWND m_myHandle;
void doSomething();
}
В этом случае MyClassImplementation сохраняет все необходимые (по крайней мере, специфичные для платформы) данные и реализует то, что необходимо (опять же, для конкретной платформы). В MyClass.cpp вы включаете реализацию конкретной платформы (методы могут быть встроенными), в конструкторе (или позже, если вы хотите - просто будьте осторожны) вы выделяете реализацию, а в деструкторе вы ее уничтожите.
Плюсы:
- Пользователь может создавать экземпляры вашего класса (в том числе в стеке) (не беспокоясь о un/deleted poiners).
- В MyClass.h не обязательно включать заголовки конкретной платформы.
- Вы можете просто добавить счетчик ссылок и реализовать совместное использование данных и/или копирование на запись, которые могут легко позволить использовать ваш класс в качестве возвращаемого значения, даже если он хранит большой объем данных.
Минусы:
- Вы должны выделить объект реализации. Пул объектов может помочь.
- При вызове методов два вызываются вместо одного разыменования указателя. Тем не менее, сегодня не должно быть никаких проблем.
4.) Определите нейтральный тип, который достаточно велик, чтобы хранить ваши данные. Например, long long int.
// MyClass.h
class MyClass
{
public:
MyClass();
void doSomething();
private:
typedef unsigned long long int MyData;
MyData m_data;
};
В реализации (например, MyClassWindows.cpp) вам всегда нужно использовать (переинтерпретировать кастинг) между MyClass:: MyData и фактическими сохраненными данными.
Плюсы:
- Как быстро, как первый, но вы избегаете макросов.
- Избегайте выделения, если не нужно.
- Предотвращение вызовов нескольких методов.
- Предотвращение включения заголовков платформы в MyClass.h.
Минусы:
- Вы должны быть на 110% уверены, что размер MyClass:: MyData всегда по крайней мере такой же, как и данные.
- Если в другой платформе хранятся данные разного размера, вы откладываете пространство (если вы используете несколько элементов, это нормально, но с миллионами их...), если вы не используете макросы. В этом случае это будет не так грязно.
- Это низкоуровневая работа с данными - небезопасная, а не ООП. Но быстро.
Итак, используйте тот, который лучше всего подходит для вашей проблемы... и ваша личность: 3, потому что сегодня сила - все четыре более или менее относительно равные по скорости и пространству.