2014-07-23 7 views
5

Ich möchte folgendes tun:Passing Member-Funktion (oder eine Umgehungs)

class A{ 
private: 
    //some data 
    B b; 
    double f(double); 
public: 
    A(){ 
    b = new B(f); // does not work of course 
    } 
}; 

class B{ 
public: 
    B(double (*func)(double)); 
}; 

Klasse B soll ein mathematisches Problem mit der Funktion func angegeben lösen. Klasse A sollte nun B verwenden, um dieses Problem für func = f zu lösen. Die Member-Funktion f greift auf die privaten Daten von A. Das Problem ist natürlich, dass ich nicht einfach einen Zeiger auf Member-Funktion übergeben kann. Ich weiß, es gibt Möglichkeiten, das zu tun, aber B sollte immer noch in der Lage sein, irgendeine Funktion zu übernehmen, nicht nur Mitglieder von A. Bisher habe ich nur f und die Mitglieder von A statische gemacht, aber ich denke, das ist ein ziemlich schlechtes Design . Können Sie sich einen Workaround dafür vorstellen?

+4

Verwenden Sie eine 'std :: -Funktion'. Wenn Sie ein Objekt für "this" in eine Elementfunktion schieben müssen, ist dies jetzt einfach möglich. Wenn die Elementfunktion 'this' nicht verwendet, mache sie zu einer freien Funktion oder' static'. – chris

+0

[Diese Frage] (http://stackoverflow.com/questions/24230726/pointer-to-a-member-function/24231066#24231066) sieht ähnlich aus. – Gluttton

+0

Danke, 'std :: function' sieht gut aus, ich werde das später versuchen. Ich bin nicht wirklich in C++ 11, vielleicht habe ich es deshalb nicht gefunden. – cthl

Antwort

2

Dies ist ein voll funktionsfähiges Programm für Ihre Probe.

#include <memory> 
#include <iostream> 
#include <functional> 

class B 
{ 
    public: 
     B(std::function<double(double)> func) 
     { 
      std::cout<<func(1.0); 
     } 
}; 

class A 
{ 
    private: 
     std::unique_ptr<B> b; 

     double f(double) 
     { 
      std::cout<<"A::f"; 
      return 2.0; 
     } 

    public: 
     A() : b(new B(std::bind(&A::f, this, std::placeholders::_1))) 
     { 
     } 
}; 

int main() 
{ 
    A a; 
} 

Bitte beachten Sie zerstören nicht b dort und auch bedenken Sie this zu B, was unterwegs sind, die gefährlich sein könnten (B könnte noch am Leben sein, nachdem A zerstört wird, und wenn Sie verwenden this innerhalb f. .. Boom!).

Ich würde auch vorschlagen Zeiger zu vermeiden und, wenn dies nicht möglich ist, mit std::unique_ptr

EDIT: Und eine Version ohne b als Zeiger, std::function und std::bind

#include <iostream> 

class A; 

class B 
{ 
    public: 
     B(A* obj, double(A::*func)(double)) 
     { 
      std::cout<<(obj->*func)(1.0); 
     } 
}; 

class A 
{ 
    private: 
     B b; 
     double f(double) 
     { 
      std::cout<<"A::f"; 
      return 2.0; 
     } 

    public: 
     A():b(this, &A::f) 
     { 
     } 
}; 

int main() 
{ 
    A a; 
} 
+1

Es sollte ein 'delete' für das' neue B (...) 'im dtor geben (oder du könntest [unique_ptr] (http://en.cppreference.com/w/cpp/memory/unique_ptr) verwenden:)) – Scis

+0

Ich weiß, ich habe gerade darauf hingewiesen, in der Antwort :) Ich wollte seinen ursprünglichen Code behalten. Ich werde es bearbeiten, weil es möglicherweise verwirrend sein könnte – Felics

+0

Danke. Ich weiß, dass ich "b" im Destruktor löschen muss. Ich habe es einfach nicht hier geschrieben, um die Dinge einfach zu halten. Ich werde jetzt die Kombination std :: function/std :: bind ausprobieren. – cthl

3

Wie wäre es mit Polymorphie als Alternative zu Ihrem aktuellen Design?

Zum Beispiel:

class A 
{ 
protected: 
    virtual double f(double x) = 0; 
}; 

class B1 : public A 
{ 
public: 
    double f(double x) {return x+1.0;} 
}; 

class B2 : public A 
{ 
public: 
    double f(double x) {return x+2.0;} 
}; 

... 

A* arr[4]; 
arr[0] = new B1; 
arr[1] = new B2; 
arr[2] = new B1; 
arr[3] = new B2; 
for (int i=0; i<4; i++) 
    cout << arr[i]->f(0.0); 
+0

Danke für Ihren Vorschlag, aber ich denke, ich kann das nicht für mein spezielles Problem verwenden. Ich muss Dutzende und Hunderte von verschiedenen Funktionen f verwenden und alle hängen von der Eingabe des Programms ab, d. H. Ich kenne sie nicht im Voraus. Außerdem arbeite ich an einer mathematischen Simulation, daher ist Leistung hier wirklich ein Problem. Mit Ihrem Design würde ich Millionen von Anrufen zu virtuellen Funktionen haben. – cthl

+0

@cthl Wahrscheinlich sind die virtuellen Aufrufe nichts im Vergleich zur eigentlichen Berechnung. Probieren Sie es aus und nehmen Sie die Optimierungen später vor, wenn sie wirklich benötigt werden. Ich würde für einen sauberen und sicheren Ansatz mit virtuellen Anrufen gehen :) – Felics

+0

@cthl: Gern geschehen. Bitte beachten Sie, dass eine virtuelle Funktion im Wesentlichen ein Funktionszeiger ist (d. H. In beiden Fällen wird eine zusätzliche Speicherladeoperation angewendet, wenn die Funktion aufgerufen wird). Es gibt also keinen Unterschied in Bezug auf die Laufzeitleistung, egal ob Sie den einen oder den anderen Mechanismus verwenden. –

3

Sie den Standard std::function<> Vorlage als polymorpher Wrapper für Ihre Funktionen nutzen kann.


Ihre Klasse B einfach eine Instanz von std::function<double (double)> speichern und nennt es durch foo:

class B 
{ 
    public: 
    B(const std::function<double (double)>& func) : func(func) {} 

    void foo(double d) 
    { 
     std::cout << func(d); 
    } 

    private: 
    std::function<double (double)> func; 
}; 

Während Ihre Klasse A mit einem seiner Mitgliedsfunktion (f) dank std::bind sein B Mitglied bauen :

class A 
{ 
    public: 
    double md; 
    B b; 

    double f(double d) const 
    { 
     return md * d; 
    } 

    public: 
    A(double d) : md(d), b(std::bind(&A::f, this, std::placeholders::_1)) { } 
}; 

Wir können jetzt sim Lage verwenden es:

int main() { 
    A a(42); 
    a.b.foo(2); // Output : 84 
} 

Live demo here.

0

Seit Funktion f() ist nicht statisch Der Typ ist "double (A :: *) (double)", nicht "double (*) (double)".

Jedoch für diesen speziellen Fall ist es besser Re-Design.

Besteht wirklich A aus Daten und Instanz des Problemlösers (Klasse B) oder besteht A aus Daten und delegiert einige Operationen an B?

Braucht die Klasse B wirklich etwas über Methoden der Klasse A zu wissen, oder erwartet sie Daten in irgendeinem Format?

class DataType {}; 
class ResultType {}; 
class A 
{ 
    DataType data; 
    DataType preprocess(Data d) {/*...*/} 
    ResultType process() { return B::compute(data); } 
    bool isSolvable() { return B::solve(preprocess(data)); } 
}; 
class B 
{ 
public: 
    ResultType compute(DataType); 
    bool solve(DataType); 
}; 
0

Mögliche Lösung:

class A 
{ 
    B* b; 
    static double f(double d); //static change function type form `double(A::*)(double)` to `double(*)(double)` 
public: 
    A() 
    { 
     b = new B(f); 
    } 
} 

einzige Nachteil, dass f alle Daten Form kippe A oder B.

Verwandte Themen