【问题标题】:How to initialize a generic base class in c++如何在 C++ 中初始化一个泛型基类
【发布时间】:2021-01-05 21:03:34
【问题描述】:

我正在尝试重写一些旧代码以使其更加面向对象。以前我有一个 structunion,比如 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,这使得代码更简洁。

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

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

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

【问题讨论】:

  • 不要混合模板和继承。任选其一。
  • 模板在正确使用时可以很好地继承。我感到困惑的是“BaseEvent”。您将它定义为一个类,然后在 EventImpl 中使用它,就像它是一个模板一样
  • @Joe,你说得对,我打算使用类继承。我仍在尝试学习 C++。 :p
  • 常见的模式是将EventImpl 作为Event 的隐藏实现。你反其道而行之。
  • 现代联合是std::variant (C++17)

标签: c++ oop c++11 dynamic-memory-allocation


【解决方案1】:

有很多不同的方法可以做到这一点。首先,您可以使用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 {};

【讨论】:

  • 是的,谢谢德米特里。我意识到命名EventImpl 可能具有误导性。 EventWrapper 是我的意思。
  • 您能否详细说明为什么shared_ptr 有点过头了?我以为我有多个事件的 ptr ..?
  • shared_ptrunique_ptr 稍重。而且您始终可以将唯一转换为共享,但反之亦然。
猜你喜欢
  • 2020-03-15
  • 2019-10-06
  • 2019-03-16
  • 1970-01-01
  • 2021-03-23
  • 1970-01-01
  • 2020-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多