[SOLVED] Passing member functions of one class to the constructor of another class using pointers.



  • Hi!

    I am trying to understand function pointers, but having a hard time with it.

    I want to create a class (ControlChaos) that takes a MultiMaps object. Now the hard part: I also want a ControlChaos (and any derived classes) instance to have access to some specific MultiMaps ( or of any of its daugther classes) member functions. I want to be able to specify those functions in the constructor of ControlChaos (or with accessor functions).

    Are there multiple ways to do this? I only thought of function pointers, but even then the syntax is not making sense to me.

    Could someone provide: (a) another solution? or (b) a simple example with function pointers?

    Here's what I have done so far (doesn't compile):

    @class ControlChaos
    {
    public:
    /*! Base constructor will be the base
    * of all control routines.
    */
    ControlChaos(MultiMaps& _map,
    mat orbitPoints,
    colvec initCond,
    double (MultiMaps::*getPara)(),
    void (MultiMaps::*setPara)(double),
    double deltaMax,
    double epsilonNeighborhood,
    int controlIterations,
    int maxIterations);
    protected:
    double (MultiMaps::*getParameter)() = NULL;
    void (MultiMaps::*setParameter)(double) = NULL;

    /* Other stuff. */
    };
    @

    And the definition:
    @
    ControlChaos::ControlChaos(MultiMaps &_map,
    mat orbitPoints,
    colvec initCond,
    double (MultiMaps::*getPara)(),
    void (MultiMaps::setPara)(double),
    double deltaMax,
    double epsilonNeighborhood,
    int controlIterations,
    int maxIterations)
    : map(_map), getParameter(getPara), setParameter(setPara)
    {
    /
    Definition (not relevant here). */
    }

    /* Function that does not compile. */
    mat ControlChaos::control()
    {
    setDefaultParameter((this->*getParameter()));
    }
    @

    where setDefaultParameter(double) is a member function that returns void. Compile sez:
    @
    dyn_controlChaos.cpp:35: error: must use '.' or '->' to call pointer-to-member function in '((ControlChaos*)this)->ControlChaos::getParameter (...)', e.g. '(... ->* ((ControlChaos*)this)->ControlChaos::getParameter) (...)'
    @

    I've tried with different dereferencing schemes, but it still doesn't work. I'm not sure what should be referenced or not.

    Complete code is available "here":http://code.google.com/p/libdynamica/source/browse/#svn/trunk and the relevant files are dyn_multiFunctor_multiMaps.* and dyn_controlChaos.*.

    Thanks everyone!



  • Hi,

    I'm not sure about the dereferencing syntax (I would have to ask google or try that out), but I am confused about the way you want to call the function. Did you maybe want to write map->*getParameter() instead of this->*getParameter() ? Since getParameter is a pointer to a member function of MultiMaps you should call it on an object of that type.
    The compiler message does not appear to be very helpful here. It would be interesting if clang gives a more useful error.



  • Yes, I thought the same thing, but the compiler gives the same error. The problem is the following. I'm trying to dereference a pointer that points to a member function in class MultiMaps. However, that pointer is itself a member variable of class ControlChaos. Just thinking about the syntax of dereferencing that makes me want to cry. A member function pointer is a member variable of another class which has no link whatsoever with the class which contains the member function I want to access.

    This "article":http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible?display=Print has some interesting stuff on member function pointers, but not what I have in mind. Is there a way to do this via templating?

    I could also make the member variables of MultiMaps and its derived classes public and simply pass their address in ControlChaos and modify them directly from the ControlChaos class, but that just seems bad programming.



  • Still, you want to call the function on the map object, so it has to appear somewhere in this line. I would try something like
    @
    map.*getParameter
    @

    or
    @
    map.*(this->getParameter)
    @



  • Did you read and understand the "FAQ":http://www.parashift.com/c++-faq-lite/pointers-to-members.html on the topic on pointers-to-member-functions?



  • Thanks Andre for the link. I've read the article and (partially) understood it. I'll be using typedef from now on. After some reflection, it seems that I'm doing something wrong. I don't see how functionoids would help me in this case.

    If, in the constructor of ControlChaos, I passed in the addresses of the functions I want to access and store them in a pointer-to-member-function that is a member variable of the class ControlChaos, would it work?

    Or, again, do you see any other way to do this? I reiterate, I want to be able to access public member functions of class MultiMaps (or rather member functions of its derived classes) from another class, ControlChaos. ControlChaos has-a MultiMaps object within it. However, the exact function to be called will vary from instance to instance.

    Thanks everyone for your time, and putting up with me.



  • Yes, the setup as such can certainly work. I use it in my current project at work as well.

    Here is a small snippet:
    @
    typedef void (ImageMetadata::IntSetterFn)(int value);
    typedef int (ImageMetadata::IntGetterFn)()const;
    class IntXmlPropertyMapper: public AbstractXmlPropertyMapper {
    public:
    IntXmlPropertyMapper(IntGetterFn getterFn, IntSetterFn setterFn,
    QString nameSpace, QString property, Level level = Default);
    virtual bool fromStream(ImageMetadata
    object, QXmlStreamReader
    reader) const;
    virtual bool toStream (const ImageMetadata* object, QXmlStreamWriter* writer) const;

    private:
    IntSetterFn m_setterFunction; //function pointer to setter function for property
    IntGetterFn m_getterFunction; //function pointer to getter function for property
    };
    @

    This class is part of a system that I use to (de-)serialize objects to/from XML, by defining a mapping. The implementation of the constructor is trivial: just a set of assignments to the relevant member variables. When called, I use this syntax:

    @
    CALL_MEMBER_FN(object,m_setterFunction)(value);
    @
    with the CALL_MEMBER_FN defined as
    @
    #define CALL_MEMBER_FN(object,ptrToMember) ((object)->*(ptrToMember))
    @
    as per in the FAQ I linked against.

    Edit:
    P.S. And no, I could not use Q_PROPERTY in this case :-)



  • Thanks! I implemented it as you did, Andre, and everything works fine.

    Apart from the weird syntax, this feature looks very useful too me. Why isn't anyone using this?

    Anyhow, for someone reading this in the future, I'd like to reiterate that the complete code is available "here":http://code.google.com/p/libdynamica/ . Happy coding!



  • Unfortunately, I think we'll have to backtrack. The code now compiles. However, it is a library, so nothing used it.

    I tried to do this on code that uses the library.

    @typedef double (HenonMap::*mapsGetPtr)();
    typedef void (HenonMap::*mapsSetPtr)(double para);
    HenonMap *hmap = &hMap;
    mapsGetPtr get = &HenonMap::getA;
    mapsSetPtr set = &HenonMap::setA;

    ControlOGY ogy = ControlOGY(hmap,fixedPoint,init,get, set,delta,epsilon,
    controlIterations,3000,contra.row(0),
    parametric.row(0));
    @

    but the compiler complains that (I left out some crap)

    @/2-OGYControl/main.cpp:264: error: no matching function for call to 'ControlOGY::ControlOGY(HenonMap*&, arma::mat&, arma::colvec&, double (HenonMap::&)(), void (HenonMap::&)(double), double&, double&, int&, int, arma::subview_row<double>, arma::subview_row<double>)'
    /usr/local/include/dynamica_bits/dyn_controlChaos_controlOGY.h:22: note: no known conversion for argument 4 from 'mapsGetPtr {aka double (HenonMap::)()}' to 'mapsGetPtr {aka double (MultiMaps::)()}'@

    where HenonMap is a derived class of MultiMaps and ControlOGY is a derived class of ControlChaos. This "article":http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible seemed to imply that it was possible to use member function pointers with inheritance.

    Since HenonMap is-a MultiMaps, I don't really see the issue.



  • Also, could "lambda functions":http://www.cprogramming.com/c++11/c++11-lambda-closures.html be used instead of function pointers?



  • Hi everyone!

    The solution is simple: before passing your pointers-to-daughter-classes to the constructor, make a simple static cast to the base class. I've tested it with the code above and everything works fine. The solution comes
    from "StackOverflow":http://stackoverflow.com/questions/11497100/accessing-a-member-function-from-another-class-without-prior-knowledge-of-the-sp.

    Have a good day, and thanks!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.