如何在C ++中初始化通用基类

问题描述

我正在尝试重写一些旧代码以使其更加面向对象。以前我有一个 struct union ,叫做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 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,从而使代码更简洁。

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

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

修改: 正如德米特里(Dmitry)指出的那样,EventImpl这个名称有点误导,EventWrapper认为更合适。 :)

解决方法

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

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重命名为EventWrapper,因为如果您使用Impl惯用语,则应使用相反的关系:

struct EventImpl;

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

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