2012-03-25 14 views
1

Ich versuche, mir selbst C++ beizubringen, und als ein erstes Projekt möchte ich Code für die Durchführung von Newton-Methode auf Funktionen einer einzelnen Variablen erstellen. Ich möchte eine Klasse ObjectiveFunction machen, die benutzerdefinierte Funktionen für die Zielfunktion, die erste Ableitung und die zweite Ableitung speichert.Member Attribute, die Funktionen in C++ sind

Ich mag der Konstruktor von ObjectiveFunction zwischen 0 und 3 Argumente nehmen, wobei die Argumente selbst Funktionen sind:

// ObjectiveFunction.h 
// Class definition for an Objective Function object. 

#ifndef OBJECTIVE_H 
#define OBJECTIVE_H 

class ObjectiveFunction 
{ 
    public: 
     // Constructors 

     // Default constructor 
     ObjectiveFunction(); 

     // Constructor with just objective function. 
     ObjectiveFunction(double f(double)); 

     // Constructor with objective function and derivative function. 
     ObjectiveFunction(double f(double), double fp(double)); 

     // Constructor with objective, derivative, and second derivative functions. 
     ObjectiveFunction(double f(double), double fp(double), double fpp(double)); 

     // Methods 
     void setObjectiveFunction(double f(dobule)); 
     void setDerivativeFunction(double f(double)); 
     void setSecondDerivativeFunction(double f(double)); 

     double evalObjectiveFunction(double); 
     double evalDerivativeFunction(double); 
     double evalSecondDerivativeFunction(double); 

    private: 
     // Storage for the functions. 
     // This is the part I'm not sure of. 

     // Attempt with function pointers 
     double (*objFunc)(double); 
     double (*d1Func)(double); 
     double (*d2Func)(double); 

}; 

#endif // OBJECTIVE_H 

Wie würde ich private Datenelemente erstellen, die selbst Funktionen sind. Ich möchte Funktionsobjekte erstellen, die (außer privat) zugänglich wären wie foo.obj_func(3.0) oder foo.deriv_func(3.0), wobei obj_func vom Konstruktor basierend auf den Funktionen, die der Benutzer an die Klasse übergibt, festgelegt wird.

Was ist der richtige Weg? Es wäre am besten, wenn es einen Weg gibt, der nicht auf einen Zeiger auf ein Funktionsobjekt angewiesen ist, aber ich denke, wenn das der einzige Weg ist, dann ist es das, was ich lernen muss.

+4

Funktion Zeiger ist genau das, was Sie brauchen (weil das ist, was Sie in Ihre Konstruktoren übergeben). –

+0

Ich habe den Abschnitt 'private' mit meinem Versuch mit Funktionszeigern geändert. Ist das die richtige Idee? – ely

+2

In C++ 11 können Sie std :: function verwenden. –

Antwort

3

Verwenden Sie std::function<double(double)>. Dadurch können Sie alle Funktionstypen einfach speichern.

+0

Wird dies in älteren C++ - Versionen unterstützt? Der andere Kommentator schlug vor, dass es nur in C++ 11 ist, das momentan nicht auf meiner Labormaschine ist. Ich kann und werde es wahrscheinlich installieren, möchte aber nicht unbedingt eine Lösung, die davon abhängt. – ely

+0

@EMS: Es gibt eine vollkommen funktionsfähige Version in Boost oder TR1, oder Sie können Ihr eigenes einfaches Äquivalent schreiben. – Puppy

+0

Ich verstehe es nicht. Ich würde annehmen, dass es Tonnen von guten Newton-Raphson C++ - Implementierungen auf der Welt gibt, aber dieses hier ist, um mir selbst beizubringen, wie man es macht. Ich fragte speziell, ob die Syntax 'std :: function' in älteren Versionen von C++ funktioniert. Wie bezieht sich der Verweis auf Boost auf die Syntax? – ely

0

Sie haben ein paar Möglichkeiten, hier zu machen, bevor sie auf eine Implementierungstechnik entscheiden ....

Nach einer ObjectiveFunction sind Sie brauchen eine Möglichkeit, um die Funktionen zu ändern, nachdem sie eingestellt worden sind? Willst du besonders flexibel sein, was du als "Funktion" akzeptierst (d. H. Werden "Funktoren" (im Prinzip alles, was den Funktionsaufruf-Operator implementiert) akzeptabel sein? Wollen Sie, dass Dinge, die eine ObjectiveFunction verwenden, in der Lage sind, beliebige austauschbare unabhängig davon zu verwenden, welche Funktionen es als Argument gegeben wurde, als Sie es konstruierten?

Sie haben hier einen sehr dynamischen Ansatz gewählt. Und die einzige Wahl, die Sie wirklich treffen müssen, ist, ob Sie einen Funktionszeiger oder ein ::std::function Objekt verwenden. Ein ::std::function Objekt kann auf alles verweisen, das den Funktionsaufrufoperator implementiert (z. B. das Ergebnis von ::std::bind). Ein Funktionszeiger kann sich nur auf eine einfache alte Funktion beziehen.

Persönlich würde ich untersuchen, eine templatized ObjectiveFunction zu haben. Teilweise weil dann die aufgerufenen Funktionen zur Kompilierzeit gesetzt werden und der Compiler sie besser optimieren kann. Mit einer Root-Finding-Technik wirst du sie sehr oft anrufen. Dies könnte Ihnen in einigen Fällen eine erhebliche Beschleunigung bringen.

+0

Mit templatized meinst du es geben eine Vorlage Art von Callable Object? In den meisten Anwendungsfällen würde ich Instanzen von 'ObjectiveFunction erstellen ... ... ist das die Idee? Warum funktioniert das Templating besser als der geänderte 'private' Abschnitt meines Codes mit 3 Funktionszeigern? In meinem Fall werden sie immer nur einfache Funktionen sein, aber ich sehe den Vorteil darin, sie allgemeiner zu gestalten, wenn ich aus irgendeinem Grund denselben Code für Funktionen verwenden möchte, die 'float' anstelle von' akzeptieren und zurückgeben doppeltes ". – ely

+0

@EMS: Ich meine templatizing, indem ich einen Typ erwarte, dessen Instanzen als Template-Argument aufrufbar sind. Dies muss kein Typ sein. Aber wenn Sie eine Instanz des Typs aufrufen, als ob es eine Funktion wäre, sollte es funktionieren. So behandeln die Standardcontainer beispielsweise die Funktionen "weniger als" oder "Hash-Funktion". – Omnifarious

0

Funktion Zeiger funktionieren oder alternativ, wenn Sie gerade eine Möglichkeit, mehrere Implementierungen ohne Änderung der aufrufenden Code zu ermöglichen, können Sie Vererbung verwenden.

Werfen Sie einen Blick auf here für einen Vergleich von Funktionszeigern vs Vererbungstechniken.

Die Vererbungslösung würde so etwas gehen; Zuerst eine Basisklasse erstellen, die die Schnittstelle implementiert, die Sie wünschen:

class BaseObjectiveFunction 
{ 
    BaseObjectiveFunction(); 
    virtual ~BaseObjectiveFunction(); 

    virtual double EvalObjectiveFunction(double); 
    virtual double EvalDerivativeFunction(double); 
    virtual double EvalSecondDerivativeFunction(double); 
} 

Dann eine vererbte Klasse implementieren, die die Funktionalität hat Sie wollen:

class LogLikelihood: public BaseObjectiveFunction 
{ 
    public: 
     LogLikelihood(); 
     ~LogLikelihood(); 

     virtual double EvalObjectiveFunction(double); 
     virtual double EvalDerivativeFunction(double); 
     virtual double EvalSecondDerivativeFunction(double); 

     // Example of a function to pass in some data which the calculations rely on 
     bool SetInputData(double* somedata, int dataLen); 
} 

Schließlich diesen Code zu nennen erstellen Sie einen Zeiger auf Ihre Basisklasse und Punkt bei der Umsetzung der Sie interessiert (in einer ähnlichen Art und Weise, dass Sie Ihre Funktionszeiger passieren würde): Dieses

LogLikelihood* pOF1 = new LogLikelihood(); // Create an instantiation of a specific solver 
BaseObjectiveFunction* pCaller = pOF1; // Establish a pointer to the interface class and at the specific implementation. 

// Now whatever calls the evaluate function can just use the pCaller and doesn't have to worry about the actual implementation. 
pCaller->EvalObjectiveFunction(1.5); 

rufen die beiden underlyi ng Implementierungen, was (denke ich) das ist, was Sie wirklich wollen.

+0

Ich glaube, Sie haben meine Verwendung der Klasse "ObjectiveFunction" missverstanden. Es ist eine Klasse, die * Elementfunktionen * aufweist, die die tatsächlichen Doppelrückgabefunktionen darstellen, die das Ziel, die erste Ableitung und die zweite Ableitung darstellen. Eine Instanz von 'ObjectiveFunction' würde nie wie eine Funktion aufgerufen werden. Stattdessen möchte ich auf seine Memberfunktionen 'someInstance.d1Func (3.0)' zugreifen, wobei 'd1Func' gesetzt wird, abhängig davon, was der Benutzer liefert, wenn' someInstance' konstruiert wurde. – ely

+0

Entschuldigung, ein paar Tippfehler drin machten, was ich weniger klar zu demonstrieren versuchte. Ich habe die obigen Beispiele mit weniger zweideutigen Namen aktualisiert. –

0
#include <stdio.h> 

class MyClass 
{ 
public: 

    typedef int(MyClass::*FunctionPointer)(int); 

    FunctionPointer func; 

    void Setup(int selector) 
    { 
     switch (selector) 
     { 
       case 1: 
       { 
        this->func = (FunctionPointer)&MyClass::Test1; 
        break; 
       } 
       case 2: 
       { 
        this->func = (FunctionPointer)&MyClass::Test2; 
        break; 
       } 
     } 
    } 

    void Call() 
    { 
     (this->*func)(10); 
    } 

    void Test1(int a) 
    { 
     printf("test1\n"); 
    } 
    void Test2(int a) 
    { 
     printf("test2\n"); 
    } 
}; 

int main() 
{ 
    MyClass *instance = new MyClass(); 

    instance->Setup(1); 
    instance->Call(); 
    instance->Setup(2); 
    instance->Call(); 

    return 0; 
} 
Verwandte Themen