2016-07-21 4 views
0

Ich werde meine Frage mit dem folgenden Beispielcode beschreiben.Vermeiden Sie den Klassenbereich, um eine Elementfunktion als Funktionszeiger zu übergeben

Ich habe Klasse B wie folgt definiert:

class B 
{ 
    public: 
     inline B(){} 
     inline B(int(*f)(int)) :myfunc{ f }{} 
     void setfunction(int (*f)(int x)) { myfunc = f; } 
     void print(int number) { std::cout << myfunc(number) << std::endl; } 
    private: 
     int(*myfunc)(int); 
}; 

ich dann Klasse A wie folgt definieren:

class A 
{ 
    public: 
    A(int myint) :a{ myint }{ b.setfunction(g); } 
    int g(int) { return a; } 
    void print() { b.print(a); } 

    private: 
    B b; 
    int a; 
    }; 

Für mich ist das Problem scheint zu sein, dass die Elementfunktion g die Signatur int A::g(int) anstatt int g(int).

Gibt es eine Standardmethode, um die oben genannten Arbeiten auszuführen? Ich denke, das ist eine ziemlich allgemeine Konfiguration, da wir eine Klasse (Klasse B) haben, die eine Art von Memberfunktionen enthält, die einige Operationen ausführen, und wir haben eine Klasse (Klasse A), die eine bestimmte Memberfunktion der Klasse verwenden muss B - so ist mein Entwurf falsch, und wenn ja, was ist der beste Weg, diese Idee auszudrücken?

+0

Ja, erklären diese Funktion 'static'. Verwenden Sie alternativ eine Interface-Klasse, in der Sie eine abstrakte Funktion definieren: virtual int g (int) = 0; Leiten Sie die Klasse 'A' von dieser Klasse ab:' Klasse A: public '. Übergeben Sie dann eine Instanz dieser Klasse an diese Funktionen in der Klasse "B". –

+2

Da Sie C++ 11/14 getaggt haben, könnte ich vorschlagen, eine 'std :: function' mit einem Lambda zu verwenden? Es wird dich ein bisschen kosten, aber es gibt keinen besseren Weg. – user975989

+0

Google "Mitglied Funktionszeiger C++" –

Antwort

3

können Sie verwenden std :: function:

class B 
{ 
public: 
    inline B() {} 
    inline B(std::function<int(int)> f) : myfunc{ f } {} 
    void setfunction(std::function<int(int)> f) { myfunc = f; } 
    void print(int number) { std::cout << myfunc(number) << std::endl; } 
private: 
    std::function<int(int)> myfunc; 
}; 

class A 
{ 
public: 
    A(int myint) :a{ myint } { 
    b.setfunction([this](int a) { 
     return g(a); 
    } 
    ); 
    } 
    int g(int) { return a; } 
    void print() { b.print(a); } 

private: 
    B b; 
    int a; 
}; 
+0

Danke für deine Hilfe und entschuldige mich, wenn das eine elementare Frage ist Ich weiß viel über std :: function und Lambda's. Also von dem, was ich verstehe [this] (int a) {umschließt g (a)} umschließt die "konstante Funktion" g (a), damit sie wie eine Funktion der Form aussieht int A:: (int) und std: : function "strip" das weiter aus damit es int (int) wird. Warum tut [] (int a) {gib g (a) zurück; } nicht arbeiten? –

+0

@DonShanil [] - is capture legt fest, welche Symbole im lamba-Body sichtbar sein sollen, g ist die Member-Funktion deiner Klasse. Wenn du es also nennen willst, musst du in [] gehen, um es möglich zu machen. – AnatolyS

1

Verwenden std::function und std::bind

class B 
{ 
    public: 
     inline B(int(*f)(int)) :myfunc{ f }{} 
     void setfunction(std::function<int(int)> f) { myfunc = f; } 
     void print(int number) { std::cout << myfunc(number) << std::endl; } 
    private: 
     std::function<int(int)> myfunc; 
}; 

// ... 
A a; 
B b(std::bind(&A::g, &a)); 

Beachten Sie auch, dass Sie die Funktion Zeiger auf einen Standardwert initialisieren sollen (höchstwahrscheinlich null) und prüfen, ob es bei der Anwendung, sonst ist es Wert nicht definiert ist.

+0

Danke Kumpel, schätze es. –

2

Sie könnten die Klasse B verallgemeinern. Statt einen Zeiger zu halten (int(*)(int)), was Sie wirklich wollen, ist jede Sache, die ich mit einer int aufrufen kann und wieder eine int bekommen. C++ 11 eingeführt, um eine Art löschte Funktion Einwand genau diesem Grund: std::function<int(int)>:

class B 
{ 
    using F = std::function<int(int)> 
public: 
    B(){} 
    B(F f) : myfunc(std::move(f)) { } 
    void setfunction(F f) { myfunc = std::move(f); } 
    void print(int number) { std::cout << myfunc(number) << std::endl; } 
private: 
    F myfunc; 
}; 

Und dann können Sie nur eine allgemeine aufrufbar in B von A bieten:

A(int myint) 
: b([this](int a){ return g(a); }) 
, a{ myint } 
{ } 
+0

Ich glaube, Sie vermissen den Platzhalter in 'std :: bind'. – Holt

+1

@Holt Danke für die Erinnerung, warum ich nie 'bind()' :) – Barry

+0

Dank Barry!Nur um zu versuchen, das "Etwas, das ich mit einem int aufrufen kann und ein anderes int zurückbekomme" zu verstehen, warum werden Standardfunktionen nicht vom Typ std :: function betrachtet. Wenn ich zum Beispiel [this] (int a) zu [&] (int a) ändere, ist alles gut, aber [] (int a) ist nicht erlaubt? –

1

Sie könnten std::bind verwenden, um die Memberfunktion A::g zu binden.

class B 
{ 
    public: 
     inline B(){} 
     inline B(std::function<int(int)> f) :myfunc{ f }{} 
     void setfunction(std::function<int(int)> f) { myfunc = f; } 
     void print(int number) { std::cout << myfunc(number) << std::endl; } 
    private: 
     std::function<int(int)> myfunc; 
}; 
class A 
{ 
    public: 
     A(int myint) :a{ myint } { 
      b.setfunction(std::bind(&A::g, this, std::placeholders::_1)); 
     } 
     int g(int) { return a; } 
     void print() { b.print(a); } 

    private: 
     B b; 
     int a; 
}; 

Hinweis benötigen Sie den Typen des Funktor von Funktionszeigern auf std::function zu ändern, die mit std::bind anwendbar ist.

LIVE

+0

Danke Kumpel, schätze es. –

Verwandte Themen