題
想象一下,我有一些模擬器庫,它從我這里獲取一些物件(又名事件處理程式)并通過呼叫它們的handle_event(Event)方法為這些物件生成事件。該庫為我提供了以下類:
class Event {}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {}; // Some event class
class AnotherParticularEvent : public Event {}; // Some event class
// Object aka event handler. I should inherit this class and then give objects to the simulator
class AbstractEventHandler
{
public:
virtual void handle_event(Event) = 0;
};
我想實作一個以不同方式處理不同事件的物件。我想出的第一個代碼如下:
#include <iostream>
class MyObject : public AbstractEventHandler
{
public:
void actual_handle_event(SomeParticularEvent)
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void actual_handle_event(AnotherParticularEvent)
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void actual_handle_event(Event e)
{
std::cerr << "Unknown event type occurred\n";
}
virtual void handle_event(Event e) override
{
actual_handle_event(e);
}
};
Сontrary對我的期望,MyObject::handle_event(Event)總是會呼叫MyObject::actual_handle_event(Event)無論動態型別的e。
我的問題是:實作的正確方法是什么MyObject(最好是可以輕松添加新的事件型別)?
所有的代碼在一起
#include <iostream>
class Event {}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {}; // Some event class
class AnotherParticularEvent : public Event {}; // Some event class
class AbstractEventHandler
{
public:
virtual void handle_event(Event) = 0;
};
class MyObject : public AbstractEventHandler
{
public:
void actual_handle_event(SomeParticularEvent)
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void actual_handle_event(AnotherParticularEvent)
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void actual_handle_event(Event e)
{
std::cerr << "Unknown event type occurred\n";
}
virtual void handle_event(Event e) override
{
actual_handle_event(e);
}
};
int main()
{
MyObject o{};
o.handle_event(SomeParticularEvent{}); // Prints "Unknown event type occurred"
}
補充問題
是否還可以在不重寫派生類中的方法的情況下創建一個派生自的類MyObject并實作額外的事件處理程式(不是覆寫舊的,而是添加對新事件的支持)handle_event?
uj5u.com熱心網友回復:
根據問題中的要求以及@ypnos 回答的評論中討論的內容,我相信您希望或需要在此處實作訪問者模式。
一種可能的實作看起來像這樣(基于維基百科關于訪問者模式的文章:https : //en.wikipedia.org/wiki/Visitor_pattern#C _example)
#include <iostream>
// Forward declare all Event classes
class Event;
class SomeParticularEvent;
class AnotherParticularEvent;
class AbstractEventHandler
{
public:
virtual void handle_event(const Event&) = 0;
virtual void handle_event(const SomeParticularEvent&) = 0;
virtual void handle_event(const AnotherParticularEvent&) = 0;
};
class Event {
public:
// virtual function for accepting the "visitor"
virtual void accept(AbstractEventHandler& handler) {
handler.handle_event(*this);
}
}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {
public:
// Needs to be overriden to call `handle_event` with the correct type
void accept(AbstractEventHandler& handler) override {
handler.handle_event(*this);
}
}; // Some event class
class AnotherParticularEvent : public Event {
public:
void accept(AbstractEventHandler& handler) override {
handler.handle_event(*this);
}
}; // Some event class
class MyObject : public AbstractEventHandler
{
public:
void handle_event(const SomeParticularEvent&) override
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void handle_event(const AnotherParticularEvent&) override
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void handle_event(const Event& e) override
{
std::cerr << "Unknown event type occurred\n";
}
};
int main()
{
MyObject o{};
SomeParticularEvent{}.accept(o);
AnotherParticularEvent{}.accept(o);
}
uj5u.com熱心網友回復:
在您的方法中handle_event()發生物件切片。您應該傳遞 (const) 參考以使繼承正常作業,或傳遞指標。
但是,當從handle_event()to內部調度時,這對您的情況沒有幫助actual_handle_event()。
一個蠻力解決方案是通過嘗試明確調度dynamic_casts。您需要handle_event()在派生類中覆寫以擴展它。它看起來也不那么漂亮(表明存在設計問題)。
在這些情況下,通常所做的是所討論的物件 ( Event) 將提供用于查詢型別的介面,例如type()被覆寫的抽象getter。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/350738.html
