Numerische Integration - Problem mit functions pointern
-
Ich bekomme den Fehler
error C2276: '&': Ungültige Operation auf Ausdruck einer gebundenen Memberfunktion
bei meinem Versuch eine Funktion als Pointer an eine Funktion zu übergeben.
Hier mein Code. Die Integrierroutine wird aufgerufen durch inttrapez, die eine Funktion als Argument erwartet, hier ist das GetCircOneDimPhaseIntegral.
double GeometricBeamShaping::GetCircOneDimPhase(const double xi) { double phase; phase = sqrt(M_PI)/2 * inttrapez(&GetCircOneDimPhaseIntegral,0,xi,100); return phase; } double GeometricBeamShaping::GetCircOneDimPhaseIntegral(double rho) { double result; result = sqrt(1-exp(-sqr(rho))); return result; }#ifndef MATHS_ARITHMETIC_INTEGRATION_H #define MATHS_ARITHMETIC_INTEGRATION_H namespace Maths{ namespace Arithmetic{ namespace Integration{ double inttrapez(double (*func)(double), const double startint, const double endint, const int steps) { double intsum = 0; double stepwidth = (endint-startint)/(double)steps; double halfstepwidth = stepwidth/2.0; for (int istep; istep<= steps; istep++) { double a = startint + stepwidth * istep; double b = a + stepwidth; double sum = halfstepwidth * ( (*func)(a) + (*func)(b) ); intsum = intsum + sum; } return( intsum ); } }; }; }; #endifWas mache ich nun falsch ?
Matthias
-
Erstens: Wo genau taucht der Fehler auf? (Nachtrag - hab ihn wohl gefunden)
Zweitens: Die Funktion inttrapez() erwartet einen Funktionszeiger, da kannst du nur globale Funktionen oder statische Methoden übergeben, keine normalen Methoden(zeiger).
Drittens: Um die Adresse einer Methode zu bestimmen, mußt du den kompletten Namen angeben -
&GeometricBeamShaping::GetCircOneDimPhaseIntegral.
-
Du kannst keine Methode an einen Funktionspointer binden, weil das this-Objekt fehlt. Mach die Methoden statisch.
-
"Memberfunktion" != "Freie Funktion"
Da musst Du eines von beiden umbauen: Entweder, indem inttrapez() etwas Anderes entgegennimmt oder indem GetCircOneDimPhaseIntegral() eine "freie Funktion" wird.
Ersteres würde ich vorziehen (weil flexibler), Zweiteres ist einfacher - gerade, weil ich überhaupt keinen Grund sehe, warum das Teil in einer Klasse steckt.
Gruß,
Simon2.
-
Simon2 schrieb:
"Memberfunktion" != "Freie Funktion"
Da musst Du eines von beiden umbauen: Entweder, indem inttrapez() etwas Anderes entgegennimmt oder indem GetCircOneDimPhaseIntegral() eine "freie Funktion" wird.
Was wäre 'etwas Anderes' oder eine 'freie Funktion' ?
Und warum darf es keine Memberfunktion sein?Simon2 schrieb:
Ersteres würde ich vorziehen (weil flexibler), Zweiteres ist einfacher - gerade, weil ich überhaupt keinen Grund sehe, warum das Teil in einer Klasse steckt.
Die Funktion ist in der Klasse weil sie außerhalb keinen Sinn ergibt.
Matthias
-
Simon2 schrieb:
Da musst Du eines von beiden umbauen: Entweder, indem inttrapez() etwas Anderes entgegennimmt oder indem GetCircOneDimPhaseIntegral() eine "freie Funktion" wird.
Ersteres ist sogar extrem einfach umzusetzen:
template< class Func > double inttrapez(Func func, const double startint, const double endint, const int steps) { double intsum = 0; double stepwidth = (endint-startint)/(double)steps; double halfstepwidth = stepwidth/2.0; for (int istep; istep<= steps; istep++) { double a = startint + stepwidth * istep; double b = a + stepwidth; double sum = halfstepwidth * ( func(a) + func(b) ); intsum = intsum + sum; } return( intsum ); }Deshalb kannst Du aber immernoch keine Methode übergeben, die nicht statisch ist. Ich würde empfehlen, das Funktionsobjekt wie hier allgemein zu halten und die Methoden statisch zu machen, da sie sowieso nicht auf nichtstatische Member zugreifen. Ansonsten müsstest Du mit etwas wie mem_fun/bind1st oder std::tr1::bind this-Objekt und Methode zu einem Funktor "zusammenbauen".
pospiech schrieb:
Und warum darf es keine Memberfunktion sein?
Wurde doch schon gesagt: Weil beim Aufruf von *func das this-Objekt fehlt.
-
pospiech schrieb:
Simon2 schrieb:
"Memberfunktion" != "Freie Funktion"
Da musst Du eines von beiden umbauen: Entweder, indem inttrapez() etwas Anderes entgegennimmt oder indem GetCircOneDimPhaseIntegral() eine "freie Funktion" wird.
Was wäre 'etwas Anderes' oder eine 'freie Funktion' ?
"etwas Anderes" wäre ein Methodenzeiger (der aber auf eine bestimmte Klasse festgelegt ist) samt this-Objekt - oder noch besser Funktor-Konstrukte über bind1st() oder boost::bind().
"freie Funktion" ist eine globale Funktion, die nicht zu deiner Klasse gehört.Und warum darf es keine Memberfunktion sein?
Eine Memberfunktion benötigt einen zusätzlichen this-Pointer, den du über einen "primitiven" Funktionszeiger nicht mitliefern kannst.
Simon2 schrieb:
Ersteres würde ich vorziehen (weil flexibler), Zweiteres ist einfacher - gerade, weil ich überhaupt keinen Grund sehe, warum das Teil in einer Klasse steckt.
Die Funktion ist in der Klasse weil sie außerhalb keinen Sinn ergibt.
Und was für einen Sinn hat sie in genau dieser Klasse? (soweit ich das überblicke, nutzt sie nur den Parameter und globale Werte/Funktionen, aber keine Klassenelemente)
-
pospiech schrieb:
...
Und warum darf es keine Memberfunktion sein?...Einfaches Gegenbeispiel (unter der falschen Annahme, es dürfte eine sein):
struct A { int member; A(int i) : member(i) {} int get() const { return member; } int calc() const { return member*2; } }; void myFunc(int (*f)()) { cout << f(); } int main() { myFunc(&A::get()); // Was soll myFunc() nun ausgeben ? return; }Ein "freier FunktionsPointer" ist sozusagen die "Adresse der Funktion im globalen Namespace", ein Memberpointer dagegen gibt die "Adresse innerhalb einer Klasse" an (so in der Art "Nimm die 3. Funktion der Klasse A").
Bei einer freien Funktion reicht das, weil sie keinen "umgebenden Status" hat wie eine Klassenfunktion....Ehrlich gesagt finde ich das auch ganz schick, weil man so nämlich Memberfunktionsangabe vom konkreten Objekt trennen kann. Z.B. (mit Obigem A)
int mit_allen(vector<A>::const_iterator& beg, vector<A>::const_iterator& end, int (A::*mf)()) { int sum = 0; vector<A>::const_iterator it(beg); while(begin != end) sum += it->mf(); return sum; } int main() { vector<A> v; fuelleVec(v); // mit vielen Daten füllen cout << mit_allen(v.begin(), v.end(), A::get) << "\n"; cout << mit_allen(v.begin(), v.end(), A::calc) << "\n"; return 0; }Wenn ich immer einen "personalisierten Memberfunktionszeiger" übergeben müsste, müsste ich jedesmal erst einen vector für jede gewünschte Memberfunktion aufbauen, den ich für nichts anderes brauche ... und ich müsste ihn immer parallel zu meinem v "mitpflegen" (also alle Veränderungen an v auch an zig verschiedenen "Memberfunktionspointer-Vektoren" nachziehen).
Gruß,
Simon2.
-
CStoll schrieb:
pospiech schrieb:
Simon2 schrieb:
"Memberfunktion" != "Freie Funktion"
Da musst Du eines von beiden umbauen: Entweder, indem inttrapez() etwas Anderes entgegennimmt oder indem GetCircOneDimPhaseIntegral() eine "freie Funktion" wird.
Was wäre 'etwas Anderes' oder eine 'freie Funktion' ?
"etwas Anderes" wäre ein Methodenzeiger (der aber auf eine bestimmte Klasse festgelegt ist) samt this-Objekt - oder noch besser Funktor-Konstrukte über bind1st() oder boost::bind().
Was ist ein 'Methodenzeiger' und was unterscheidet es von einem normalen Zeiger?
Und was für einen Sinn hat sie in genau dieser Klasse? (soweit ich das überblicke, nutzt sie nur den Parameter und globale Werte/Funktionen, aber keine Klassenelemente)
Die Klasse liefert mir einen berechneten Laserstrahl inklusive Phase und ist abgeleitet von einer wesentlich größeren Klasse.
Und Funktionen die nur innerhalb der Klasse sinn machen definiere ich normalerweise nicht als freie Funktionen.
Matthias
-
pospiech schrieb:
CStoll schrieb:
pospiech schrieb:
Simon2 schrieb:
"Memberfunktion" != "Freie Funktion"
Da musst Du eines von beiden umbauen: Entweder, indem inttrapez() etwas Anderes entgegennimmt oder indem GetCircOneDimPhaseIntegral() eine "freie Funktion" wird.
Was wäre 'etwas Anderes' oder eine 'freie Funktion' ?
"etwas Anderes" wäre ein Methodenzeiger (der aber auf eine bestimmte Klasse festgelegt ist) samt this-Objekt - oder noch besser Funktor-Konstrukte über bind1st() oder boost::bind().
Was ist ein 'Methodenzeiger' und was unterscheidet es von einem normalen Zeiger?
Siehe dazu die Ausführungen von Simon (für genauere Informationen empfielt sich google).
(@Simon: sollte die get()-Methode nicht 'return member;' sagen?)
Und was für einen Sinn hat sie in genau dieser Klasse? (soweit ich das überblicke, nutzt sie nur den Parameter und globale Werte/Funktionen, aber keine Klassenelemente)
Die Klasse liefert mir einen berechneten Laserstrahl inklusive Phase und ist abgeleitet von einer wesentlich größeren Klasse.
Und Funktionen die nur innerhalb der Klasse sinn machen definiere ich normalerweise nicht als freie Funktionen.
Matthias
Wenn dir global zu weitreichend ist, kannst du solche Hilfsfunktionen gerne in einen eigenen Namensraum auslagern. Schließlich kannst du nicht wissen, ob eine identische Berechnung nicht noch irgendwo anders gebraucht wird.
In die Klasse gehören (imho) nur Funktionen, die direkten Bezug zu den Membern der Klasse benötigen. Alles andere bläht sie nur unnötig auf
-
pospiech schrieb:
...
Und Funktionen die nur innerhalb der Klasse sinn machen definiere ich normalerweise nicht als freie Funktionen...."Freie Funktion" bedeutet ja nicht, dass sie im globalen namespace liegen muss. Hier würde ich sie in vielleicht denselben namespace legen wie die Klasse ...
Du argumentierst IMHO falsch herum: Eine Memberfunktion macht etwas mit der Klasse.
=> Wenn eine Funktion nichts "mit der Klasse" macht, hat sie den Memberklassenstatus nicht verdient.
Es gibt natürlich Funktionen, die sehr eng mit einer Klasse verheiratet sind und trotzdem "nichts mit ihr machen" - die können dann "static" sein und auch genauso verwendet werden wie freie Funktionen.
Gruß,
Simon2.
-
pospiech schrieb:
Was ist ein 'Methodenzeiger' und was unterscheidet es von einem normalen Zeiger?
Begriffserklärung:
Ich verwende im weiteren Text den Begriff Methode für Funktionen einer Klasse, und Funktion für freie Funktionen die keinen Klassebezug haben.Auch wenn schon mehrere Versuche unternommen wurden, versuche ich es jetzt etwas anders. Auf eine Methode greifst du über ein Objekt zu, bei einer statischen Methode oder einer Funktion brauchst du dies nicht (bei ersteren musst du zwar die Klasse angeben, aber das nur damit er sie findet).
Beispiel (ich bringe absichtlich auch den this-Zeiger ins Spiel):
class A { ... private: int value; public: void SetValue(int value) { this->value = value; } static void foo() {}; ... }; void foo { } int main() { A a; A b; // SetValue(2); -- geht nicht, bezug fehlt a.SetValue(1); b.SetValue(2); A::foo(); // Klassenbezug zum finden nötig, aber kein Objekt foo(); // Normale Funktion ohne Klassenbezug }Also was ist der Unterschied zwischen einen Methoden und ein Funktionszeiger?
Der Funktionszeiger kennt kein Objekt, und arbeitet daher nur mit normalen Funktionen oder statischen Methoden zusammen.
Ein Methodenzeiger benötigt aber eben dieses: Ein Objekt. Den von welchen Objekt soll er den die Methode aufrufen. Hier kommt der this-Zeiger in das Spiel. Sprich der Zeiger auf das jeweilige Objekt.
Jetzt gehen wir ein wenig tiefer in die Materie: Was macht ein Compiler eigentlich aus einer nicht-statischen Methode?
// Aus class A { ... private: int value; public: void SetValue(int value) ... }; // wird Intern etwas das dem folgenden entspricht: struct A { int value; }; void SetValue(A* this, int value) { this->value = value; // Jetzt sollte man auch den this-Zeiger ein wenig verstehen... }Sprich: Ein Funktionszeiger kann deshalb nicht auf nicht-statische Methoden verweisen, da ihm der "this"-Zeiger fehlt (wie schon von anderen gesagt, hier nur etwas ausgearbeitet)
cu André