2017-10-25 4 views
2

Ich schreibe einen Spielecode mit C++. Ich möchte die Memberfunktion Child in einen Delegaten binden.Mitglied Functor der Inherited Class

Ich möchte init_and_bind Funktion wie dieser vereinfachten Code verwenden:

class Parent { 
protected: 
    Widget* widget; 
}; 

class Child : public Parent { 
public: 
    void foo() { 
     widget->init_and_bind(this, &Child::bar); 
    } 

    void bar() { /* do something */ } 
}; 

Ich möchte init_and_bind in Widget Klasse implementieren, so implementiert I wie unten Code:

// pre-defined in engine 
void Delegate::bind(Parent* object, void(Parent::* function)()); 

void Widget::init_and_bind(Parent* object, void(Parent::* function)()) { 
    init(); 
    delegate->bind(object, function); 
} 

Aber es funktioniert nicht Arbeit. Weil der zweite Parameter von init_and_bind nur den Member-Funktortyp von Parent akzeptiert. Also kann ich nicht Mitglied Funktor von Child übergeben. Also habe ich versucht Vorlage zu verwenden und reinterpret_cast:

template<typename T> 
void Widget::init_and_bind(Parent* object, void(T::* function)()) { 
    init(); 
    delegate->bind(object, function); // error 
    delegate->bind(object, reinterpret_cast<void(Parent::*)()>(function); // error 
} 

Aber es ist auch nicht funktionieren. Weil es nicht gelungen ist, den Funktor Child auf Parent 's Funktor zu werfen.

Also, welcher Typ sollte init_and_bind 's zweites Argument sein?

+2

'static_cast', nicht' reininterpret_cast'. – StoryTeller

+0

@StoryTeller Oh es funktioniert, danke! Aber ich weiß nicht, warum 'reiniterpret_cast' nicht kompiliert wird. –

+1

Verschiedene Formen für verschiedene Jobs. Der Compiler prüft, ob Sie das für das Richtige verwenden. Beginnen Sie immer mit einem 'static_cast', wenn Sie überhaupt casten müssen. – StoryTeller

Antwort

2

Während die sofortige Lösung zu static_cast ist, sollten Sie nicht init_and_bind in eine Vorlage drehen. Der generierte Code wird immer gleich sein. Der einzige Unterschied besteht möglicherweise darin, wie die tatsächliche Besetzung ausgeführt wird.

Sie werden also eine Menge Code-Bloat bekommen, alles wegen eines sehr kleinen Unterschieds. Ich schlage vor, dass Sie diesen Unterschied stattdessen einkapseln. Fügen Sie einen Helfer Typ Widget dafür:

class Widget { 
    struct MemFunc { 
    void(Parent::* function)(); 
    template<class T> 
    MemFunc(void(T::* func)()) : 
     function(static_cast<void(Parent::*)()>(func)) 
    {} 
    }; 

    void init_and_bind(Parent* object, MemFunc mf) { 
    init(); 
    delegate->bind(object, mf.function); 
    } 
}; 

Auf diese Weise nur die sehr kleine Stück Code, das Templat als Templat ist in der Tat muss. Was am besten ist, geschieht transparent auf der Anruferseite. Und es wird wahrscheinlich nicht einmal zu Blähungen führen. Weil Ihre ursprüngliche Nicht-Template-Version den Anrufer sowieso auf static_cast erfordert.