У меня была идея нестандартного способа обработки многоплатформенных интерфейсов в C ++, и я хотел бы знать, если это вообще плохая идея и почему.
В настоящее время я могу думать только об одном недостатке: это очень (?) Необычно делать что-то подобное и, возможно, не совсем понятно, как это работает на первый взгляд:
У меня есть класс, который будет использоваться на разных платформах, например CMat4x4f32 (матричный класс 4×4, использующий 32-разрядные числа с плавающей запятой).
Мой независимый от платформы интерфейс выглядит так:
class CMat4x4f32
{
public:
//Some methods
#include "Mat4x4f32.platform.inl"};
Mat4x4f32.platform.inl выглядит так:
public:
// Fills the matrix from a DirectX11 SSE matrix
void FromXMMatrix(const XMMatrix& _Matrix);
Он просто добавляет платформо-зависимый интерфейс к классу матрицы.
.Cpp и Mat4x4f32.platform.inl расположены внутри подпапок, таких как «win32» или «posix», поэтому в win32 я реализую функцию FromXMMatrix. Моя система сборки добавляет эти подпапки в путь включения в зависимости от платформы, для которой я собираюсь.
Я мог бы даже сделать шаг вперед и реализовать .platform.cpp, который находится внутри win32 и содержит только те функции, которые я добавляю в интерфейс для этой платформы.
Я лично считаю, что это хорошая идея, потому что она делает написание и использование интерфейсов очень простым и чистым.
Особенно в моей библиотеке Renderer, в которой интенсивно используется класс Matrix из моей базовой библиотеки, теперь я могу использовать зависящие от платформы функции (FromXMMatrix) в части DirectX, как будто у меня нет других платформ, о которых нужно беспокоиться.
В самой базовой библиотеке я все еще могу писать независимый от платформы код, используя общий матричный интерфейс.
У меня также есть другие классы, где это полезно: например, класс Error, который собирает ошибки и автоматически переводит их в читаемые сообщения и предоставляет некоторые параметры отладки.
Для win32 я могу создавать экземпляры ошибок из плохих DirectX и Win32 HResults, а в Linux я могу создавать их из возвращенных ошибок. В базовой библиотеке у меня есть класс, который управляет этими ошибками, используя общий интерфейс ошибок.
Это сильно уменьшает необходимый код и предотвращает появление уродливой платформы в зависимости от классов утилит.
Так это плохой или хороший дизайн и каковы альтернативы?
Похоже, вы говорите об использовании шаблона моста:
http://c2.com/cgi/wiki?BridgePattern
По своему личному опыту я разработал много платформо-независимых интерфейсов, со специфическими реализациями, использующими этот шаблон, и он работал очень хорошо, я часто использовал его с идиомой Pimpl:
http://c2.com/cgi/wiki?PimplIdiom
Как и в альтернативах, я обнаружил, что этот сайт в целом очень хорош для объяснения плюсов & минусы различных моделей и парадигм:
http://c2.com/cgi/wiki
Я бы порекомендовал вам использовать вместо этого «pimpl»:
class CMat4x4f32
{
public:
CMat4x4f32();
void Foo();
void Bar();
private:
std::unique_ptr<CMat4x4f32Impl> m_impl;
};
А затем в конфигах build-file извлекаются специфичные для платформы .cpp файлы, где вы, например, определяете функции, специфичные для вашей платформы:
class CMat4x4f32::CMat4x4f32Impl
{
public:
void Foo() { /* Actual impl */ }
void Bar() { /* Actual impl */ }
// Fills the matrix from a DirectX11 SSE matrix
void FromXMMatrix(const XMMatrix& _Matrix);
};
CMat4x4f32::CMat4x4f32() : m_impl(new CMat4x4f32Impl()) {}
CMat4x4f32::Foo() { m_impl->Foo(); }
CMat4x4f32::Bar() { m_impl->Bar(); }