Учитывайте ситуацию при создании кросс-платформенного многопоточного приложения.Использовать экземпляр абстрактного класса в кросс-платформенном коде
Итак, когда вы это сделаете, вы, вероятно, разделите функциональность платформы между некоторыми классами. Например, вам нужна простая консоль для вывода некоторого текста в ваше приложение. Возможный способ сделать это - объявить некоторый абстрактный класс Console
, а затем, когда вам это нужно на какой-то платформе, наследовать от него и использовать экземпляры производных классов.
Все в порядке, пока не выяснится, что нужен экземпляр Console
(например, как член класса). Вы знаете, что если вы попытаетесь объявить переменную-член класса Console
в каком-то другом классе, вы получите ошибку, потому что экземпляры абстрактных классов недопустимы. Но вам все еще нужен этот класс, так как вы считаете, что при компиляции производный класс будет реализован, и он будет правильным, но вы не знаете имя этого класса или могут быть разные имена в зависимости от платформы.
Вот сложный пример.
При разработке кросс-платформенного многопоточного приложения вам нужно что-то вроде Syncer
(Synchronizer). Аналогом этого является объект mutex в Windows API.
Вы знаете, что в зависимости от платформы этот класс будет отличаться. Но вы знаете, что есть некоторые методы, которые будет иметь любой вариант платформы. Например, эти методы: lock
и unlock
. Как вы не знаете, как будут эти методы можно сделать, вы объявляете их чисто виртуальными, как в следующем:
class Syncer
{
public:
virtual void lock()=0;
virtual void unlock()=0;
}
И теперь, развивая некоторый класс, вы понимаете, что вам не нужно одно, но многое из этого Syncer
-s. Но вы не можете этого сделать, поскольку класс абстрактный.
Возможные решения, которые я нашел являются:
1) Использование шаблонов. Например:
template<class syncer>
class SyncUser
{
public:
syncer syncInstance;
SyncUser()
{
syncInstance().lock;
}
Но проблема в том, что пользователь может вставить класс вместо syncer
параметра в любой другой класс (бы он или нет, это не имеет значения, он может это сделать.).. Таким образом, решение не так хорошо, как ожидается общее решение.
2) Использовать макросы. При использовании таким образом, содержание Syncer.h
будет, как в следующем:
class Syncer
{
public:
virtual void lock()=0;
virtual void unlock()=0;
}
#ifdef PLATFORM1
#include "platform1_sync_implement.h"
#else
#include "platform2_sync_implement.h"
#endif
когда файл "platform1_sync_implement.h"
имеет следующее:
#include "Syncer.h"
class SyncPlatform1 : public Syncer
{
//Correct implementation
}
#define Syncer SyncPlatform1
Теперь, кто включен Syncer.h
бы иметь реализованный вариант. Но этот способ также не очень хорош, так как требуется список платформ, где будет реализована абстракция Sync
. Это не так хорошо для больших проектов, так как вам просто нужно объявить этот класс и заботиться о том, чтобы другие программисты могли его использовать.
Итак, вопрос: есть ли лучший способ использовать «экземпляр» абстрактного класса, зная, что его дочерний класс будет реализован где-то.
P.С .: Я знаю, что это не лучшее имя для такого вопроса. P.P.S .: Извините за плохой английский.
tl; dr .. короткий ответ - нет «экземпляра абстрактного класса». По определению абстрактные классы не могут быть созданы – user463035818
Я не убежден в вашей мотивации. Полиморфизм виртуальных функций предназначен для обработки различных реализаций * во время выполнения *. Вариант использования нескольких платформ, по-видимому, не имеет решений во время выполнения. Ваша программа не выполняет * в то же время * на игровом автомате и на игровой станции. Скорее, вы перекомпилируете для каждой платформы. –
На самом деле я не понимаю проблему, если вы хотите, чтобы объект, который был получен из абстрактного класса в качестве члена другого класса, вы можете иметь указатель на этот абстрактный класс как член – user463035818