Информация об изменениях

Сообщение Re: Интерфейсы и реализации от 06.03.2024 0:57

Изменено 06.03.2024 1:08 rg45

Re: Интерфейсы и реализации
Здравствуйте, Marty, Вы писали:

M>Обычно, если реализация зависит от платформы, не парюсь и делаю абстрактный интерфейс с чисто виртуальными функциями, делаю реализацию под target-платформу, а фабрика создаёт объект в куче и возвращает указатель на интерфейс, голенький или shared.


M>Из плюсов — можно при необходимости даже в рамках одной платформы и в рамках одного приложения сделать разные реализации и при необходимости использовать ту или иную реализацию, с возможностью выбора в рантайме.


Ну вот тут желательно сразу определиться с потребностями. Переносимость на различные платформы — это одно, а возможность выбора реализации в рантайме — совсем другое. Если тебе действительно нужно переключаться между реализациями в рантайме, то ты на правильном пути.

M>В общем, как бы и на елку залезть, и жопу не ободрать?

M>Есть идеи, как сделать шоколадно?

Если говорить вообще о переходе от динамического полиморфизма к статическому, безотносительно данной задачи, то тут принцип не очень сложный — то, что было абстрактным интерфейсом становится концептом. Но тут главное без фанатизма — не обязательно описывать концептами прямо все-все подряд. В каждой задаче есть набор каких-то относительно статичных сущностей — типов и констант, для которых кастомизация не очень актуальна — ну так пусть эти типы и константы такими и остаются. При необходимости их можно использовать при определении концептов.

template <typename T>
concept Cursor = std::default_initializable<T> && BooleanTestable<T>;

template <typename T>
concept Window =
requires (const T& w) {
   // Constant properties:
   {w.GetSize()} -> std::same_as<Vector<2, int>>;
   {w.GetPos()} -> std::same_as<Vector<2, int>>;
   {w.GetCursor()} -> Cursor;
} &&
requires (T& w, Vector<2, int> v, Cursor auto cursor) {
   // Modifying operations:
   w.SetSize(v);
   w.SetPos(v);
   {w.SetCursor(cursor)} -> Cursor;
   {w.createStockCursor(std::declval<EStockCursor>())} -> Cursor;
};


Потом набрасываешь классы реализаций и тут же можно проверять их на соответствие концептам:

class WinWindows
{
public:
   GetSize() . . .
   SetSize() . . .
   GetCursor() . . .
   SetCursor() . . .
};

// Concept check:
static_assert(Windows<WinWindows>);
Re: Интерфейсы и реализации
Здравствуйте, Marty, Вы писали:

M>Обычно, если реализация зависит от платформы, не парюсь и делаю абстрактный интерфейс с чисто виртуальными функциями, делаю реализацию под target-платформу, а фабрика создаёт объект в куче и возвращает указатель на интерфейс, голенький или shared.


M>Из плюсов — можно при необходимости даже в рамках одной платформы и в рамках одного приложения сделать разные реализации и при необходимости использовать ту или иную реализацию, с возможностью выбора в рантайме.


Ну вот тут желательно сразу определиться с потребностями. Переносимость на различные платформы — это одно, а возможность выбора реализации в рантайме — совсем другое. Если тебе действительно нужно переключаться между реализациями в рантайме, то ты на правильном пути.

M>В общем, как бы и на елку залезть, и жопу не ободрать?

M>Есть идеи, как сделать шоколадно?

Если говорить вообще о переходе от динамического полиморфизма к статическому, безотносительно данной задачи, то тут принцип не очень сложный — то, что было абстрактным интерфейсом становится концептом. Но тут главное без фанатизма — не обязательно описывать концептами прямо все-все подряд. В каждой задаче есть набор каких-то относительно статичных сущностей — типов и констант, для которых кастомизация не очень актуальна — ну так пусть эти типы и константы такими и остаются. При необходимости их можно использовать при определении концептов.

template <typename T>
concept Cursor = std::default_initializable<T> && BooleanTestable<T>;

template <typename T>
concept Window =
requires (const T& w) {
   // Constant properties:
   {w.GetSize()} -> std::same_as<Vector<2, int>>;
   {w.GetPos()} -> std::same_as<Vector<2, int>>;
   {w.GetCursor()} -> Cursor;
} &&
requires (T& w, Vector<2, int> v, Cursor auto cursor) {
   // Modifying operations:
   w.SetSize(v);
   w.SetPos(v);
   {w.SetCursor(cursor)} -> Cursor;
   {w.createStockCursor(std::declval<EStockCursor>())} -> Cursor;
};


Потом набрасываешь классы реализаций и тут же можно проверять их на соответствие концептам:

class WinWindow
{
public:
   GetSize() . . .
   SetSize() . . .
   GetCursor() . . .
   SetCursor() . . .
};

// Concept check:
static_assert(Window<WinWindow>);