OVH Cloud OVH Cloud

Pointeur sur fonction membre

8 réponses
Avatar
Boris Sargos
Salut,

je viens de lire les différents posts sur les pointeurs de fonctions
membres, mais je n'ai pas réussi à obtenir de réponse à mon problème. Il est
le suivant:
Je dispose d'une classe NewtonRootFinder, qui comme son nom l'indique, est
chargée de retourner le zéro d'une fonction, qu'on lui passe en paramètre :
double (*FonctionZero)(double).
Ailleurs dans mon code, j'ai besoin de trouver le zéro d'une fonction :

class MyClass {
double MyClass::FonctionZero(double) { ... } // Fonction dont on
cherche à calculer le zéro
void MyClass::Calcule(void) {
NewtonRootFinder finder;
finder.SetFonction(FonctionZero); // Je passe le
pointeur de fonction en paramètre à mon RootFinder
double resultat = finder.FindZero(); // La fonction
FindZero de l'objet finder calcule le zéro de la fonction membre
MyClass::FonctionZero
}
}

Or cela ne compile pas (et pour cause), puisque finder a besoin d'une
instance de MyClass pour lui appliquer FonctionZero.
Mais je n'ai pas d'autre solution. J'ai aussi regardé les objets fonctions
de la stl (unary_function et mem_func) mais sans résultat, je restez coincé
car NewtonRootFinder doit pouvoir accepter tout type de fonction (membre ou
pas membre) et il n'existe aucune classe qui surclasse unary_function.

Quelqu'un a une solution ?

Merci à tous, et bon week-end.

8 réponses

Avatar
Loïc Joly
Boris Sargos wrote:

Salut,

je viens de lire les différents posts sur les pointeurs de fonctions
membres, mais je n'ai pas réussi à obtenir de réponse à mon problème. Il est
le suivant:
Je dispose d'une classe NewtonRootFinder, qui comme son nom l'indique, est
chargée de retourner le zéro d'une fonction, qu'on lui passe en paramètre :
double (*FonctionZero)(double).
[...]


Quelqu'un a une solution ?


Ce que j'ai trouvé de plus simple, c'est de dire que le paramètre qu'on
passe à NewtonRootFinder est non pas de type
double(*FonctionZero)(double), mais de type boost::function<double(double)>

Pour ça, il faut pouvoir modifier NewtonRootFinder.

--
Loïc

Avatar
Christophe Lephay
Boris Sargos wrote:
Je dispose d'une classe NewtonRootFinder, qui comme son nom
l'indique, est chargée de retourner le zéro d'une fonction, qu'on lui
passe en paramètre : double (*FonctionZero)(double).
Ailleurs dans mon code, j'ai besoin de trouver le zéro d'une fonction
:

class MyClass {
double MyClass::FonctionZero(double) { ... } // Fonction dont on
cherche à calculer le zéro
void MyClass::Calcule(void) {
NewtonRootFinder finder;
finder.SetFonction(FonctionZero); // Je passe le
pointeur de fonction en paramètre à mon RootFinder
double resultat = finder.FindZero(); // La
fonction FindZero de l'objet finder calcule le zéro de la fonction
membre MyClass::FonctionZero
}
}

Or cela ne compile pas (et pour cause), puisque finder a besoin d'une
instance de MyClass pour lui appliquer FonctionZero.


Le probème, c'est que sans voir ta classe NewtonRootFinder, c'est un peu dur
de t'aider (ton erreur de compilation a probablement peu à voir avec le fait
d'avoir une instance ou non de MyClass)...

Chris

Avatar
Jean-Marc Bourguet
"Boris Sargos" writes:

Quelqu'un a une solution ?


Tu peux faire un objet capable d'encapsuler aussi bien un
pointeur vers fonction et une paire objet, pointeur vers
fonction membre et l'utiliser comme paramètre pour ta
fonction NewtonRootFinder.

Exemple (non vérifié):

class DoubleFunctionBase {
public:
virtual double operator()(double) const = 0;
};

class DoubleFunctionPointer: public DoubleFunctionBase {
public:
DoubleFunctionPointer(double (*fn)(double)) : myFn(fn) {}
double operator()(double d) const { return (*myFn)(d); }
private:
double (*myFn)(double);
};

template <typename T>
class DoubleFunctionMember: public DoubleFunctionBase {
public:
DoubleFunctionMember(T& obj, double (T::*fn)(double))
: myObj(obj), myFn(fn) {}
double operator()(double d) const { return (myObj.*myFn)(d); }
private:
T& myObj;
double (T::*myFn)(double);
};

DoubleFunctionPointer makeFunc(double (*fn)(double))
{
return DoubleFunctionPointer(fn);
}

template <typename T>
DoubleFunctionMember<T> makeFunc(T& obj, double (T::*fn)(double))
{
return DoubleFunctionMember<T>(obj, fn);
}

double NewtonRootFinder(DoubleFunctionBase const& fn) {
return fn(0);
}

double f(double);
class A {
public:
double g(double);
};

int main() {
A a;
NewtonRootFinder(makeFunc(f));
NewtonRootFinder(makeFunc(a, A::g));
}

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Boris Sargos
Merci Jean-Marc pour ta réponse.

Peu avant de lire ta réponse, j'avais pensé à cette méthode. C'est efficace.
Mais je me suis rendu compte qu' en fait, cela revient pratiquement à
recréer une partie de l'architecture <functional> de la stl. C'est un peu
dommage, d'autant plus que si j'y vois assez clair, on se prive du coup de
l'utilisation de mem_fun et bind ...
Mais je pense que c'est une solution satisfaisante.
Encore merci.
Avatar
Boris Sargos
Ok, c'est toujours difficile de résumer son code par mail. En fait, ma
classe NewtonRootFinder n'a que deux fonctions :
- SetFunction : stocke la fonction à analyser
- FindZero : moteur de calcul pour trouver le zéro de la fonction
membre.
Puis elle a un membre : m_function qui est la fonction à analyser (fonction
réelle à valeurs réelles) . C'est tout (j'ai omis les détails techniques du
genre intervalle de calcul, précision, etc ...).
Merci.
Avatar
Boris Sargos
Ok, mais c'est quoi boost ?

Merci.
Avatar
Loïc Joly
Boris Sargos wrote:
Ok, mais c'est quoi boost ?


www.boost.org

--
Loïc

Avatar
Boris Sargos