gpt4 book ai didi

C++函数不接受具体实现

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:38:42 25 4
gpt4 key购买 nike

我正在尝试实现类型安全的事件总线。我坚持使用 EventBus::subscribe 函数,因为它不接受我的具体事件处理程序。在较早的版本中,我只将 AbstractEventHandler 实现为抽象类,而不是模板。我对该实现没有任何问题。这就是为什么我认为实际问题出在抽象模板上。

下面的代码是我的实现的精简版本。第一个 block 由事件总线的“骨架”及其所需的类组成,而第二个 block 显示事件、事件处理程序和主体的实际实现。

enum 包含所有可用的不同事件。抽象事件是所有具体事件派生的基础。事件处理程序是一个抽象模板,以事件作为模板类以确保类型安全。事件总线负责将所有已发布的事件分发到其各自的处理程序。

enum EVENT_TYPE 
{
ON_EVENT_1,
ON_EVENT_2
};

class AbstractEvent
{
public:
AbstractEvent() {};
virtual ~AbstractEvent() {};

virtual EVENT_TYPE type() = 0;
};

template<class T>
class AbstractEventHandler
{
public:
AbstractEventHandler() {};
virtual ~AbstractEventHandler() {};

virtual void on_event(T *event) = 0;
};

class EventBus
{
public:
EventBus() {};
virtual ~EventBus() {};

void subscribe(EVENT_TYPE type,
AbstractEventHandler<AbstractEvent> *eventHandler) {
// Add handler to vector for further use
}

void publish(AbstractEvent *event) {
// send event to each handler in respective vector
}
};

下面是我的具体事件和事件处理程序以及 main()

class ConcreteEvent : public AbstractEvent 
{
public:
ConcreteEvent() {};
virtual ~ConcreteEvent() {};

EVENT_TYPE type() {
return ON_EVENT_1;
};
};

class ConcreteEventHandler : public AbstractEventHandler<ConcreteEvent>
{
public:
ConcreteEventHandler() {}
virtual ~ConcreteEventHandler() {};

void on_event(ConcreteEvent *event) {
// Do something
};
};

int main()
{
EventBus *eventBus = new EventBus();

ConcreteEventHandler handler = ConcreteEventHandler();

// This failes!
eventBus->subscribe(ON_EVENT_1, &handler);
}

编译器返回一个错误,指出没有匹配的函数来调用

EventBus::subscribe(EVENT_TYPE, ConcreteEventHandler*) 

而且唯一的候选人是

void EventBus::subscribe(EVENT_TYPE, AbstractEventHandler<AbstractEvent>*) 

如何实现我的 EventBus::subscribe 方法来接受抽象类的具体实现?

更新:解决方案

我已将 EventBus::subscribe 的方法描述更改为以下内容,现在它运行良好:

template<typename T>
void subscribe(EVENT_TYPE type, AbstractEventHandler<T> *eventHandler) {

}

谢谢 Rohan 的提示!他们帮助我找到了这个解决方案。

最佳答案

原因是因为,ConcreteEventHandlerAbstractEventHandler<ConcreteEvent> 的子类而不是 AbstractEventHandler<AbstractEvent> .

这可能看起来令人惊讶,但是 AbstractEventHandler<ConcreteEvent>不能是 AbstractEventHandler<AbstractEvent> 的子类尽管 ConcreteEventAbstractEvent 的子类.

原因是,使用模板,随心所欲地制作模板并不能保证类型安全。让我们看一个例子。让我们回顾一下基类的标准范例 Animal和子类 CatDog .假设我们有一个动物列表:

std::list<Animals>* animals;

和猫的列表:

std::list<Cat> cats;

以下不是有效的转换:

animals = &cats;

原因是,如果我要这样做,

animals->add(new Dog("Ben"));

我实际上会添加一个 DogCat 的列表秒。 cats.last()这里实际上会返回一个 Dog .因此,在这种情况下,您实际上是在添加一个 Dog。到 Cat 的列表秒。我看过足够多的 Looney Tunes 剧集,知道这不是一个好主意:

cats.last().meow();

以上肯定不是真的,因为我们都知道一个Dog只能bowbow() .

编辑

为了回答您的问题,我建议您这样做;让ConcreteEventHandler继承自 AbstractEventHandler<AbstractEvent> , 在代码中,无论你在哪里使用 ConcreteEvent , 使用 dynamic_case类型转换AbstractEventConcreteEvent .这将使用运行时自省(introspection),这可能会稍微影响性能(我也看到很多人反对使用动态转换),但您将能够成功执行数据类型的有效向上转换。

关于C++函数不接受具体实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9972968/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com