2012-03-25 2 views
1

Я пытаюсь научить себя C++ и как исходный проект, я хочу создать код для выполнения метода Ньютона для функций одной переменной. Я хочу создать класс ObjectiveFunction, который хранит пользовательские функции для целевой функции, первой производной и второй производной.Атрибуты членов, которые являются функциями в C++

Я хочу, чтобы конструктор ObjectiveFunction принимать от 0 до 3-х аргументов, когда сами аргументы являются функциями:

// 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 

Как бы я создавать частные элементы данных, которые сами являются функциями. Я хочу создать объекты функций, которые (за исключением частного) будут доступны, например, foo.obj_func(3.0) или foo.deriv_func(3.0), где obj_func устанавливается конструктором на основе функций, которые пользователь передает классу.

Каков правильный способ сделать это? Было бы лучше, если бы был способ, который не полагался бы на использование указателя на объект функции, но я думаю, если это единственный способ, то это то, что мне нужно будет изучить.

+4

Указатели функций - это именно то, что вам нужно (потому что это то, что вы передаете своим конструкторам). –

+0

Я изменил раздел 'private' кода с моей попыткой с указателями функций. Это правильная идея? – ely

+2

В C++ 11 вы можете использовать std :: function. –

ответ

3

Использование std::function<double(double)>. Это позволит вам легко хранить все типы функций.

+0

Поддерживается ли это в старых версиях на C++? Другой комментатор предположил, что это только на C++ 11, который в настоящее время не работает на моей лабораторной машине. Я могу и, возможно, его установлю, но не обязательно хочу, чтобы от него зависело решение. – ely

+0

@EMS: В Boost или TR1 есть совершенно функциональная версия, или вы можете написать свой собственный простой эквивалент. – Puppy

+0

Не понимаю. Я бы предположил, что в мире существует множество хороших реалий Ньютона-Рафсона C++, но это для того, чтобы научить себя, как это сделать. Я задал вопрос о том, работает ли синтаксис 'std :: function' в более старых версиях C++. Как ссылка на Boost связана с синтаксисом? – ely

0

У вас есть несколько вариантов, чтобы сделать здесь до принятия решения о реализации методики ....

После создания ObjectiveFunction будет вам нужен способ, чтобы изменить функции после того, как они были установлены? Вы хотите быть более гибкими в отношении того, что вы принимаете в качестве «функции» (т. Е. Будут ли «функторы» (в основном что-либо, реализующие оператор вызова функции))? Вам нужны вещи, которые используют ObjectiveFunction, чтобы использовать любые ObjectiveFunction взаимозаменяемые, независимо от того, какие функции он дал в качестве аргумента, когда вы его построили?

Здесь вы выбрали очень динамичный подход. И единственный выбор, который вам действительно нужно сделать, - это использовать указатель функции или объект ::std::function. Объект ::std::function может ссылаться на все, что реализует оператор вызова функции (например, результат ::std::bind). Указатель функции может ссылаться только на обычную старую функцию.

Лично я бы расследовал с templatized ObjectiveFunction. Частично, потому что тогда функции, которые он вызывает, будут установлены во время компиляции, и компилятор сможет лучше оптимизировать их. С помощью метода поиска корней вы будете называть их много. Таким образом, это может привести к значительному ускорению в некоторых случаях.

+0

Применяя templatized, вы имеете в виду предоставление ему типа шаблона вызываемого объекта? Поэтому в большинстве случаев я бы создал экземпляры 'ObjectiveFunction ' ... это идея? Почему подобные шаблоны работают лучше, чем измененный раздел 'private' моего кода с 3 указателями функций? В моем случае они будут только когда-либо выполняться в простых функциях, но я вижу, что он лучше его разрабатывает, если не по какой-либо другой причине, чем я хотел бы использовать тот же код для функций, которые принимают и возвращают 'float' вместо' double'. – ely

+0

@EMS: Я имею в виду templatizing, ожидая, что экземпляры типа, вызываемые в качестве аргумента шаблона. Это, в частности, не должно быть какого-либо типа. Но если вы вызываете экземпляр типа, как если бы он был функцией, он должен работать. Так стандартные контейнеры обрабатывают такие вещи, как функции «меньше» или «хэш». – Omnifarious

0

Функциональные указатели будут работать или, альтернативно, если вы только после того, как разрешите несколько реализаций без изменения кода вызова, вы можете использовать наследование.

Посмотрите here для сравнения указателей функций и методов наследования.

Решение наследования будет выглядеть примерно так: Сначала нужно создать базовый класс, который реализует интерфейс, который вы хотите:

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

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

Затем реализовать унаследованный класс, который имеет функциональность вы хотите:

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); 
} 

Наконец, чтобы назвать этот код вы создаете указатель на ваш базовый класс и точка реализации, вы заинтересованы в (сходным образом, который вы передаете свои указатели на функции):

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); 

Это будет вызывать два underlyi ng, которые (я думаю), что вы действительно хотите здесь.

+0

Я думаю, вы неправильно поняли мое использование класса 'ObjectiveFunction'. Это класс, который * имеет функции-члены *, которые являются действительными функциями двойного возврата, представляющими цель, первую производную и вторую производную. Экземпляр 'ObjectiveFunction' никогда не будет вызван как функция. Скорее, я хочу получить доступ к его функциям-членам, 'someInstance.d1Func (3.0)', где 'd1Func' устанавливается в зависимости от того, что пользователь предоставляет при создании' someInstance'. – ely

+0

Извинения, несколько опечаток там сделали то, что я пытался продемонстрировать, менее ясны. Я обновил приведенные выше примеры с менее двусмысленными именами. –

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; 
} 
Смежные вопросы