首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >由于签名差异而调用了错误的子类函数

由于签名差异而调用了错误的子类函数
EN

Stack Overflow用户
提问于 2020-01-22 04:00:13
回答 2查看 71关注 0票数 1

我有一个发出事件的事件发射器和处理事件的事件处理程序。我可以扩展Event对象来创建不同的事件,比如AlarmEvent,并扩展EventHandler对象来创建AlarmEventHandlerEventHandler有一个函数HandleEvent(Event &event)。这会给可能具有HandleEvent(AlarmEvent &event)方法的子类带来问题。显然,这是两个不同的函数,所以这里不会发生重写。相反,我需要让HandleEvent被子类覆盖。

我完全理解问题所在,因为每个EventHandler都有不同的HandleEvent签名,所以EventEmitter总是使用基本EventHandler::HandleEvent来处理事件。我认为通过使用Event &event作为EventEmitter::Emit的参数,它将知道它处理的是哪种类型的Event,并选择正确的方法。

如何让我的EventEmitter调用AlarmEventHandler::HandleEvent而不是基方法EventHandler::HandleEvent

代码语言:javascript
运行
复制
// Example program
#include <iostream>
#include <string>
#include <vector>

// event types
class Event {};
class AlarmEvent : public Event {};

// event handler
class EventHandler {
    public:
        virtual void HandleEvent(Event event);
};
void EventHandler::HandleEvent(Event event){
    std::cout << "Handle event " << std::endl;   
}

// alarm event handler
class AlarmEventHandler : public EventHandler {
    public:
        void HandleEvent(AlarmEvent event);  
};
void AlarmEventHandler::HandleEvent(AlarmEvent event){
    std::cout << "Handle alarm event " << std::endl;   
}

// event emitter
class Emitter {
    public:  
        std::vector<EventHandler*> handlers;
        void Emit(Event &event);
};
void Emitter::Emit(Event &event){
    for(size_t i = 0; i < this->handlers.size(); i++){
        this->handlers[i]->HandleEvent(event);   
    }
}

int main()
{
    AlarmEventHandler handler;
    AlarmEvent event;
    Emitter emitter;
    emitter.handlers.push_back(&handler);
    // problem:
    // Handle event printed instead of Handle alarm event
    emitter.Emit(event);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-22 04:07:39

使用dynamic_cast

因此,您的AlarmEventHandler可能如下所示:

代码语言:javascript
运行
复制
// alarm event handler
class AlarmEventHandler : public EventHandler {
    public:
        void HandleEvent(const Event &event); // Our polymorphic override
        void HandleEvent(AlarmEvent event);  // Our custom Alarm logic
};

void AlarmEventHandler::HandleEvent(const Event &event){
    try {
        HandleEvent(dynamic_cast<const AlarmEvent&>(event));
    } catch(const std::exception& e) {
        std::cerr << "I can't handle things that aren't AlarmEvents!" << std::endl;
    }
}

void AlarmEventHandler::HandleEvent(const AlarmEvent &event){
    std::cout << "Handle alarm event " << std::endl;   
}

不过,要做到这一点,您需要让Event成为一个多态类。所以你把析构函数设为virtual

代码语言:javascript
运行
复制
class Event { 
    public: virtual ~Event() {} //Need this so Event is a polymorphic class
};

在这里查看它的运行:https://ideone.com/KMkLfq

票数 3
EN

Stack Overflow用户

发布于 2020-01-22 04:28:54

您没有重写HandleEvent(),而是重载了它。

您需要一个指针或引用,以便能够利用动态分派而不必强制转换。

内联注释:

代码语言:javascript
运行
复制
#include <iostream>
#include <string>
#include <vector>

// event types
class Event {
    public:
        virtual ~Event();                       // make base destructor virtual
};

Event::~Event() {}

class AlarmEvent : public Event {};

// event handler
class EventHandler {
    public:
        virtual void HandleEvent(Event& event);
        virtual ~EventHandler();                 // virtual base destructor
};

EventHandler::~EventHandler() {}

void EventHandler::HandleEvent(Event& event){
    std::cout << "Handle event " << std::endl;   
}

// alarm event handler
class AlarmEventHandler : public EventHandler {
    public:
        //void HandleEvent(AlarmEvent& event);  // overload, does not override
        void HandleEvent(Event& event);
};

void AlarmEventHandler::HandleEvent(Event& event){
    std::cout << "Handle alarm event " << std::endl;   
}

// event emitter
class Emitter {
    public:
        Emitter() : handlers() {}
        std::vector<EventHandler*> handlers;
        void Emit(Event &event);
};

void Emitter::Emit(Event& event) {
    for(size_t i = 0; i < this->handlers.size(); i++){
        this->handlers[i]->HandleEvent(event);   
    }
}

int main() {
    AlarmEventHandler handler;
    AlarmEvent event;
    Emitter emitter;
    emitter.handlers.push_back(&handler);
    emitter.Emit(event);
}

使用编译

代码语言:javascript
运行
复制
g++ -std=c++98 -O3 -Wall -Wextra -Weffc++ -pedantic -pedantic-errors

输出:

代码语言:javascript
运行
复制
Handle alarm event 
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59848372

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档