#c #oop #c 11 #dynamic-memory-allocation
#c #ооп #c 11 #динамическое выделение памяти
Вопрос:
Я пытаюсь переписать некоторый старый код, чтобы сделать его более объектно-ориентированным. ранее у меня вызывалось объединение struct, скажем Event
union Event {
AEvent aEvent;
BEvent bEvent;
CEvent cEvent;
}
и это Event
позже используется в структуре
struct EventImpl {
... //some other members
Event event();
}
теперь я пытаюсь использовать мощный shared_ptr
;
Я создал новый базовый класс с именем BaseEvent
class BaseEvent{
size_t m_TypeHash;
public:
using Ptr = std::shared_ptr<BaseEvent>;
virtual ~EventDesc() = default;
template <class T>
// cast to different events
static std::shared_ptr<T> Cast(const Ptramp; src) {
return src->m_TypeHash == typeid(T).hash_code()
? std::static_pointer_cast<T>(src)
: nullptr;
}
protected:
BaseEvent(size_t typeHash) : m_TypeHash(typeHash){}
};
Отсюда, AEvent
, BEvent
и CEvent
может просто расширяться BaseEvent
, что делает код более чистым.
Но возникает вопрос, что мне делать со структурой EventImpl
, которая содержит Event
?? Есть ли способ инициализировать универсальный BaseEvent
класс?
struct EventImpl {
... //some other members
BaseEvent<T> event; //??
T event; // ??
std::shared_ptr<BaseEvent> event; // ???
}
редактировать:
название EventImpl
немного вводит в заблуждение, как указал Дмитрий, EventWrapper
считает более подходящим. 🙂
Комментарии:
1. Не смешивайте шаблоны и наследование. Выберите один или другой.
2. Шаблоны хорошо переносят наследование при правильном использовании. Что меня смущает, так это «BaseEvent». Вы определяете его как класс, но затем используете его в EventImpl, как если бы это был шаблон
3. @Joe, ты прав, я намеревался использовать наследование классов. Я все еще пытаюсь освоить c . : p
4. Общий шаблон заключается в том, чтобы иметь
EventImpl
скрытую реализациюEvent
. Вы делаете обратное.5. современное объединение — это
std::variant
(C 17)
Ответ №1:
Есть много разных способов сделать это. Прежде всего, вы можете использовать std::variant
в качестве более ориентированной на ООП альтернативы union
:
using Event = std::variant<AEvent, BEvent, CEvent>;
Другой подход заключается в использовании динамического полиморфизма: вам нужно определить базовый класс для всех XEvent
типов:
class BaseEvent {};
class AEvent : public BaseEvent {};
Другой аспект динамического полиморфизма заключается в том, как возвращать значение: по необработанному указателю, по ссылке, интеллектуальному указателю и т. Д. Это std::shared_ptr
может быть излишним, std::unique_ptr
это должна быть первая идиома, которую следует учитывать.
struct EventWrapper {
std::unique_ptr<Event> event();
};
Я намеренно переименовал EventImpl
to EventWrapper
, потому что, если вы используете Impl
идиому, следует использовать противоположное отношение:
struct EventImpl;
class Event {
std::unique_ptr<EventImpl> _impl;
};
class AEventImpl : public EventImpl {};
class BEventImpl : public EventImpl {};
class CEventImpl : public EventImpl {};
Комментарии:
1. да, спасибо, Дмитрий. Я понял, что именование
EventImpl
, вероятно, вводит в заблуждение.EventWrapper
это то, что я имел в виду.2. и не могли бы вы уточнить, почему это
shared_ptr
излишество? Я думал, что у меня есть несколько ptr для события ..?3.
shared_ptr
Немного тяжелее, чемunique_ptr
. И вы всегда можете преобразовать unique в shared, но не наоборот.