簡體   English   中英

將非模板基類向下轉換為模板化派生類:是否可能?

[英]Downcasting non-template base class to templated derived class: is it possible?

我正在為游戲實現一個事件系統。 它使用事件隊列和數據結構來保存給定事件類型的所有已注冊事件處理程序。 它到目前為止注冊處理程序工作正常,但是當取消注冊它們時(例如,當游戲對象被銷毀時會發生這種情況)我在模板和轉換方面遇到了一些麻煩。

我已經將EventHandler定義為某種函子,部分基於Szymon Gatner在http://www.gamedev.net/reference/programming/features/effeventcpp/上的文章。 確切地說,我使用了HandlerFunctionBase和MemberFunctionHandler類定義並提出了:

class BaseEventHandler
{
public:
    virtual ~BaseEventHandler(){}
    void handleEvent(const EventPtr evt)
    {
        invoke(evt);
    }
private:
    virtual void invoke(const EventPtr evt)=0;
};

template <class T, class TEvent>
class EventHandler: public BaseEventHandler
{
    public:
    typedef void (T::*TMemberFunction)(boost::shared_ptr<TEvent>);
    typedef boost::shared_ptr<T> TPtr;
    typedef boost::shared_ptr<TEvent> TEventPtr;

    EventHandler(TPtr instance, TMemberFunction memFn) : mInstance(instance), mCallback(memFn) {}

    void invoke(const EventPtr evt)
    {
        (mInstance.get()->*mCallback)(boost::dynamic_pointer_cast<TEvent>(evt));
    }
    TPtr getInstance() const{return mInstance;}
    TMemberFunction getCallback() const{return mCallback;}

    private:
        TPtr mInstance;
    TMemberFunction mCallback;
};

然后我想到的EventManager類上的unregisterHandler()方法的初始實現將如下所示:

// EventHandlerPtr is a boost::shared_ptr<BaseEventHandler>.
// mEventHandlers is an STL map indexed by TEventType, where the values are a std::list<EventHandlerPtr>
void EventManager::unregisterHandler(EventHandlerPtr hdl,TEventType evtType)
{
    if (!mEventHandlers.empty() && mEventHandlers.count(evtType))
    {
        mEventHandlers[evtType].remove(hdl);
        //remove entry if there are no more handlers subscribed for the event type
    if (mEventHandlers[evtType].size()==0)
        mEventHandlers.erase(evtType);
    }
}

為了使“刪除”工作在這里,我想到為BaseEventHandler重載==運算符,然后使用虛方法來執行實際比較...

bool BaseEventHandler::operator== (const BaseEventHandler& other) const
{
    if (typeid(*this)!=typeid(other)) return false;
    return equal(other);
}

並且,在模板類EventHandler上,實現抽象方法'equal',如下所示:

bool  equal(const BaseEventHandler& other) const
{
    EventHandler<T,TEvent> derivedOther = static_cast<EventHandler<T,TEvent>>(other);
    return derivedOther.getInstance() == this->getInstance() && derivedOther.getCallback()==this->getCallback();
}

當然,我在static_cast行上遇到編譯錯誤。 我甚至不確定是否可以進行演員表演(不一定使用static_cast)。 有沒有辦法執行它,或者至少有一些解決方法可以解決這個問題?

在此先感謝=)

通常,在關閉模板時,您需要確保>由空格分隔,因此編譯器不會將它們解析為右移運算符。

在這里,您嘗試靜態轉換對非引用的引用,即使它工作也可以調用對象切片。 您需要靜態強制轉換為派生引用。

bool  equal(const BaseEventHandler& other) const
{
    EventHandler<T,TEvent>& derivedOther = static_cast<EventHandler<T,TEvent>&>(other);
    return derivedOther.getInstance() == this->getInstance() && derivedOther.getCallback()==this->getCallback();
}

謝謝Mark和Steve:這讓我朝着正確的方向前進。 還有另外一個問題,因為我試圖將一個const轉換為非const,但之后這個更容易被發現。

經過一些調整后,這就是我最終得到的結果:

void EventManager::unregisterHandler(EventHandlerPtr hdl,TEventType evtType)
{
    if (!mEventHandlers.empty() && mEventHandlers.count(evtType))
    {
        TEventHandlerList::iterator newEnd=remove_if(mEventHandlers[evtType].begin(),
            mEventHandlers[evtType].end(),EventHandlerComparisonFunctor(hdl));
        mEventHandlers[evtType].erase(newEnd,mEventHandlers[evtType].end());
        if (mEventHandlers[evtType].size()==0)
            mEventHandlers.erase(evtType);
    }
}

我用remove_if更改了remove ,因為boost :: shared_ptr通過直接比較指針而不是它們的內容來實現==運算符。 現在,極其命名的EventHandlerComparisonFunctor負責執行相等性檢查。

它實現如下:

class EventHandlerComparisonFunctor
{
private:
    EventHandlerPtr mInstance;
public:
    EventHandlerComparisonFunctor(EventHandlerPtr instance):mInstance(instance){}
    bool operator()(EventHandlerPtr& other) const
    {
        return *(mInstance.get())==*(other.get());
    }
};

最后,在EventHandler中使用了相等的方法( @gf ,該方法確實是在EventHandler模​​板中聲明的,但出於某種原因我將其剪切掉以將類代碼粘貼到此處,我的錯誤)

bool equal(const BaseEventHandler& other) const
{
    EventHandler<T,TEvent>& derivedOther = static_cast<EventHandler<T,TEvent>&>(const_cast<BaseEventHandler&>(other));
    return derivedOther.getInstance() == this->getInstance() && derivedOther.getCallback()==this->getCallback();
}

現在一切正常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM