2010-12-03 11 views
5

Bitte beachten Sie den folgenden Code. Eine virtuelle Funktion über einen Funktionszeiger statisch aufrufen

#include <iostream> 
#include <memory> 

struct A { 
    A() {} 
    virtual void f() { 
    std::cout << "A::f" << std::endl; 
    } 
private: 
    A(const A&); 
}; 

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    call(&A::f); 
    } 
private: 
    void call(void (A::*aMethod)()) { 
    // ... 
    (static_cast<A&>(*this).*aMethod)(); 
    //(static_cast<A>(*this).*aMethod)(); -> not allowed to copy! 
    // ... 
    } 
}; 

void main() { 
    std::auto_ptr<B> b (new B); 
    b->f(); 
} 

Dieser Code rekursiv ruft die gleichen B::f Verfahren, bis es aus Stapel läuft, während ich die call Methode möchte A::f zu nennen. Das heißt, es sollte es statisch nennen, wie es normalerweise geschehen hätte, würde ich einfach geschrieben:

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    // ... 
    A::f(); 
    // ... 
    } 
}; 

Der Grund, warum ich die call Methode haben will, ist einigen Code vor und nach dem ‚statischen Aufruf‘ Faktor, der gemeinsam ist zu mehreren Methoden mit der gleichen Signatur wie f ...

Wie kann ich eine virtuelle Funktion statisch aufrufen, die zur Laufzeit entschieden wird?

+0

In 'B :: f', warum müssen Sie die Funktion über' Call' und einen Funktionszeiger aufrufen? Warum kannst du nicht einfach 'A :: f();'? (Refactoring der "Vorher" und "Nachher" -Code in einige gemeinsame Funktionen oder eine gemeinsame Klasse.) –

+0

Das ist wahrscheinlich, was ich tun muss ... Methode 'Call' war nur hier, um den Code herauszufiltern, aber ich hatte nicht realisiert Ich könnte es nicht so verwenden, wie ich es wollte ... –

Antwort

4

Das wird erwartet. Der Objektausdruck ist eine Referenz auf die Basisklasse A und daher wird der virtuelle Funktionsmechanismus (dynamische Bindung) ausgelöst, da A :: f virtuell ist.

Nur der Operator :: kann den Mechanismus für virtuelle Funktionsaufrufe unterstützen.

$ 10,3/12- "Explicit Qualifikation mit dem Umfang Operator (5.1) unterdrückt den virtuellen Call-Mechanismus."

+0

Und es scheint, ich kann den Scope-Operator hier nicht verwenden: Er würde den Namen des Pointers qualifizieren, nicht die Funktion, auf die verwiesen wird ... –

+0

Ja , AFAICT, müssen Sie gehen mit A :: f – Chubsdad

1

Ihre Überschreibung ist gelöst, wenn Sie den Zeiger nehmen, also was Sie hier wollen, ist nicht so leicht möglich. Das Beste, was Sie tun können, ist ein Wrapper, der Ihre Funktion aufruft - entweder eine externe oder eine nicht-virtuelle Funktion, die Ihre Funktion aufruft. Wenn Sie C++ 0x-Features haben, könnten Sie ein Lambda verwenden, das die sauberste Lösung IMO ist.

Vielleicht möchten Sie die Art und Weise, wie Sie Pre-/Post-Funktionen ausführen, noch einmal überdenken, um Ihr Problem anzugehen: Sie können durch Überladen des Operators "->" implementiert werden.

+0

Leider ist das Überladen von Operator-> im realen Fall nicht anwendbar, weil es für jede aufgerufene Methode gelten würde, nicht nur für f und die anderen, die ähnlich sind ... Aber trotzdem danke ... –

+0

Ja, das ist normalerweise ein Problem. Sie können Ihren Code jedoch möglicherweise umgestalten, um nur diese Methoden in eine separate Schnittstellenklasse zu integrieren. Oder wenden Sie einfach den Wrapping-Operator auf der Call-Site Ihrer virtuellen Funktionen an, wie Call (myObject) -> f(); – ltjax

+0

Eigentlich muss man gar nicht überladen -> für diese letzte Idee. Es genügt, nur ctor und dtor eines "Call" -Typs zu implementieren. – ltjax

Verwandte Themen