如何在 C++ 中初始化泛型基 class

How to initialize a generic base class in c++

我正在尝试重写一些旧代码以使其更加面向对象。以前我有一个 union of struct 调用,比如说 Event

union Event {
  AEvent aEvent;
  BEvent bEvent;
  CEvent cEvent;
}

而这个Event后来在结构

中使用
struct EventImpl {
  ... //some other members 
  Event event();
}

现在我正在尝试使用强大的shared_ptr; 我创建了一个名为 BaseEvent

的新基地 class
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 Ptr& src) {
            return src->m_TypeHash == typeid(T).hash_code() 
                ? std::static_pointer_cast<T>(src)
                : nullptr;
        }
    protected: 
        BaseEvent(size_t typeHash) : m_TypeHash(typeHash){}
};

从这里开始,AEventBEventCEvent 可以扩展 BaseEvent,这使代码更清晰。

但是问题来了,我如何处理包含Event的结构体EventImpl?有没有办法初始化泛型 BaseEvent?

struct EventImpl {
  ... //some other members 
  BaseEvent<T> event; //??
  T event; // ??
  std::shared_ptr<BaseEvent> event; // ???
}

编辑EventImpl 这个名字有点误导,正如 Dmitry 指出的那样,EventWrapper 认为更合适。 :)

有很多不同的方法可以做到这一点。首先,您可以使用 std::variant 作为 OOP-aware 替代 union:

using Event = std::variant<AEvent, BEvent, CEvent>;

另一种方法是使用动态多态性:您需要为所有 XEvent 类型定义一个基础 class:

class BaseEvent {};

class AEvent : public BaseEvent {};

动态多态的另一个方面是如何 return 值:通过原始指针、通过引用、智能指针等。std::shared_ptr 可能有点矫枉过正,std::unique_ptr应该是第一个考虑的成语。

struct EventWrapper {
  std::unique_ptr<Event> event();
};

我故意将 EventImpl 重命名为 EventWrapper 因为如果你使用 Impl 成语,则应使用相反的关系:

struct EventImpl;

class Event {
    std::unique_ptr<EventImpl> _impl;
};

class AEventImpl : public EventImpl {};
class BEventImpl : public EventImpl {};
class CEventImpl : public EventImpl {};