How to invoke the methods of an object selecting them from a table

Discussion in 'C++' started by Stefano Sabatini, Feb 5, 2008.

  1. This is my solution for subject:

    #include <string>
    #include <iostream>

    using namespace std;

    class DumbThing {
    public:
    void sayFoo() { cout << "Foo!" << endl; }

    static void sayFoo(DumbThing &t) {
    t.sayFoo();
    }

    void sayBar() { cout << "Bar!" << endl; }

    static void sayBar(DumbThing &t) {
    t.sayBar();
    }
    };

    struct ClassMethod {
    string name;
    void (*method)(DumbThing &);
    };

    int main(void) {

    struct ClassMethod DumbThingMethods[] = {
    { "sayFoo", &DumbThing::sayFoo },
    { "sayBar", &DumbThing::sayBar }
    };

    int DumbThingMethodsNum = sizeof(DumbThingMethods) / sizeof(ClassMethod);

    DumbThing t;
    for (int i=0; i < DumbThingMethodsNum; i++)
    DumbThingMethods.method(t);

    return 0;
    }

    The problem with this solution is that I have to create for each
    method a corresponding static function, can you contrive a solution
    which doesn't require this?

    Many thanks in advance for any advice.
     
    Stefano Sabatini, Feb 5, 2008
    #1
    1. Advertisements



  2. Sorry for replying to self.

    After some thinking I found a satisfying solution, which makes use of
    pointers to member and it sounds like this:

    #include <string>
    #include <iostream>

    using namespace std;

    class DumbThing {
    public:
    void sayFoo() { cout << "Foo!" << endl; }
    void sayBar() { cout << "Bar!" << endl; }
    };

    struct ClassMethod {
    string name;
    void (DumbThing::*method)();
    };

    int main(void) {

    struct ClassMethod DumbThingMethods[] = {
    { "sayFoo", &DumbThing::sayFoo },
    { "sayBar", &DumbThing::sayBar }
    };

    int DumbThingMethodsNum = sizeof(DumbThingMethods) / sizeof(ClassMethod);

    DumbThing t;
    for (int i=0; i < DumbThingMethodsNum; i++)
    (t.*DumbThingMethods.method)();

    return 0;
    }

    Greetings.
     
    Stefano Sabatini, Feb 5, 2008
    #2
    1. Advertisements

  3. Stefano Sabatini

    Ondra Holub Guest



    To call method, when you have pointer to this method, you need class
    instance too. It is not needed for static methods (which are from this
    point of view global functions with different visibility), but you
    cannot call class method without instance.

    For this purpose is used either .* operator or ->* operator. There may
    be confusing the syntax, how it is used (due to operator priority).
    Use it this way:

    DumbThing dt;
    DumbThing* dtp = &dt;
    void (DumbThing::*method)() = &DumbThing::sayFoo;

    (dt.*method)(); // Call method via pointer when you have instance
    (dt->*method)(); // Call method via pointer when you have pointer to
    instance
     
    Ondra Holub, Feb 5, 2008
    #3
  4. Stefano Sabatini

    Sam Guest



    You want to use class member pointers:

    // Declare:

    class Foo {

    public:
    void x();
    void y();
    };

    // Don't use arrays, when you really want a map:

    std::map<std::string, void (Foo::*)() > methods;

    // Initialize:

    methods["x"]= &Foo:x;
    methods["y"]= &Foo:y;

    // Invoke some method on an object.

    void callFoo(Foo *obj, std::string methodname)
    {
    std::map<std::string, void (Foo::*)() >::iterator p=
    methods.find(methodname);

    if (p == methods.end())
    throw "You are a bozo";

    (obj->*(p->second))();
    }



    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.7 (GNU/Linux)

    iD8DBQBHqFJRx9p3GYHlUOIRAjQKAJ9SyKDHF8LQp/dJ9VwY/L9MZ/KcuACeIzwA
    ZMvZoGtyo21uvpeIpqAIUoQ=
    =CYcU
    -----END PGP SIGNATURE-----
     
    Sam, Feb 5, 2008
    #4


  5. Hi Ondra and Sam, yes I finally got in touch with the
    member pointers feature of C++, thank you so much for your hints and
    explanations!! :)

    I already posted a solution using the memeber pointers, well now I see
    I should rather use std::map rather than a plain array.

    Best regards.
     
    Stefano Sabatini, Feb 5, 2008
    #5
  6. And here it is a solution using map:

    #include <string>
    #include <iostream>
    #include <map>

    using namespace std;

    class DumbThing {
    public:
    void sayFoo() { cout << "Foo!" << endl; }
    void sayBar() { cout << "Bar!" << endl; }
    };

    int main(void) {
    // declare a map
    map<string, void (DumbThing::*)() > methods;

    // initialize it
    methods["sayFoo"] = &DumbThing::sayFoo;
    methods["sayBar"] = &DumbThing::sayBar;

    map<string, void (DumbThing::*)() >::iterator it;

    DumbThing t;
    for (it=methods.begin() ; it != methods.end(); it++ ) {
    cout << "Invoking method: " << (*it).first << endl;
    (t.*(it->second))();
    }

    return 0;
    }

    Best regards.
     
    Stefano Sabatini, Feb 5, 2008
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.