problem with function pointers

Discussion in 'C++' started by TheOne, Mar 15, 2005.

  1. TheOne

    TheOne Guest

    I have two classes:
    class OntologyParser
    {
    ...

    protected:

    virtual void startElement(void *userData, const char *name, const
    char **atts);
    virtual void endElement(void *userData, const char *name);
    virtual void charData( void *userData, const XML_Char *s, int len );

    ....
    public:
    void initXMLParse(const string& fname);
    .....
    };

    This class is a base class for

    class ProtegeOntologyParser : public OntologyParser
    {
    public:


    inline ProtegeOntologyParser(const string& strFileName)
    {
    initXMLParse(strFileName);
    }

    };

    I am using G++ on RedHat 9.0 Linux with Expat library.

    The initXMLParse function is common to all (here just
    ProtegeOntologyParser) derived classes hence I want to keep that in
    parent class. The functions startElement, endElement and charData must
    be implemented separately by all derived classes.

    However the problem is expat needs call backs setup for startElement,
    endElement and charData functions from within initXMLParse like this:

    void OntologyParser::initXMLParse(const string& fname)
    {
    char buffer[BUFSIZ];
    int len;
    int done;
    int depth = 0;

    //Get the Parser
    XML_Parser parser = XML_ParserCreate(NULL);

    //User Data Handler
    XML_SetUserData(parser, &depth);

    //Element Level Handler
    XML_SetElementHandler(parser, startElement, endElement);

    //Set What to do with the data
    XML_SetCharacterDataHandler( parser, charData );

    ....
    }

    But the functions that I pass there as argument must be the functions
    of derived classes and right function addresses should be passed based
    upon which object was responsible for invoking initXMLParse().

    As you know ISO C++ forbids somthing like &(this->charData)
    Secondly i do not want to make those 3 function static. and they must
    be "virtual" in the base class so that all derived classes are forced
    to implement them.

    How can I pass those arguments?
     
    TheOne, Mar 15, 2005
    #1
    1. Advertising

  2. "TheOne" <> wrote...
    >I have two classes:
    > class OntologyParser
    > {
    > ...
    >
    > protected:
    >
    > virtual void startElement(void *userData, const char *name, const
    > char **atts);
    > virtual void endElement(void *userData, const char *name);
    > virtual void charData( void *userData, const XML_Char *s, int len );
    >
    > ....
    > public:
    > void initXMLParse(const string& fname);
    > .....
    > };
    >
    > This class is a base class for
    >
    > class ProtegeOntologyParser : public OntologyParser
    > {
    > public:
    >
    >
    > inline ProtegeOntologyParser(const string& strFileName)
    > {
    > initXMLParse(strFileName);
    > }
    >
    > };
    >
    > I am using G++ on RedHat 9.0 Linux with Expat library.
    >
    > The initXMLParse function is common to all (here just
    > ProtegeOntologyParser) derived classes hence I want to keep that in
    > parent class. The functions startElement, endElement and charData must
    > be implemented separately by all derived classes.
    >
    > However the problem is expat needs call backs setup for startElement,
    > endElement and charData functions from within initXMLParse like this:
    >
    > void OntologyParser::initXMLParse(const string& fname)
    > {
    > char buffer[BUFSIZ];
    > int len;
    > int done;
    > int depth = 0;
    >
    > //Get the Parser
    > XML_Parser parser = XML_ParserCreate(NULL);
    >
    > //User Data Handler
    > XML_SetUserData(parser, &depth);
    >
    > //Element Level Handler
    > XML_SetElementHandler(parser, startElement, endElement);
    >
    > //Set What to do with the data
    > XML_SetCharacterDataHandler( parser, charData );
    >
    > ....
    > }
    >
    > But the functions that I pass there as argument must be the functions
    > of derived classes and right function addresses should be passed based
    > upon which object was responsible for invoking initXMLParse().
    >
    > As you know ISO C++ forbids somthing like &(this->charData)
    > Secondly i do not want to make those 3 function static.


    But how would expat call them? It requres them to be callbacks of some
    particular signature which probably does not have anything to do with
    your classes. You have no choice but to make them static.

    > and they must
    > be "virtual" in the base class so that all derived classes are forced
    > to implement them.


    The derived classes are not going to be forced unless those functions
    are declared pure.

    > How can I pass those arguments?


    Make the three functions static. Let expat pass the 'userdata' as
    void* and static_cast it to your base class in each function. Then
    call your "real" processing functions, which should be virtual, using
    that base class pointer. The derived function should be called.

    ---------------------------------------
    struct Caller { // your expat emulator
    void (*int_callback)(void*,int);
    void (*double_callback)(void*,double);
    void* ptr;

    void init_ptr(void* p) { ptr = p; }
    void init_int_cb(void (*icb)(void*,int)) { int_callback = icb; }
    void init_dbl_cb(void (*dcb)(void*,double)) { double_callback =
    dcb; }

    void do_something() {
    int_callback(ptr, 666);
    double_callback(ptr, 3.1415926);
    int_callback(ptr, 42);
    }
    };

    struct Base {
    Caller *caller;

    Base() : caller(new Caller) { caller->init_ptr(this); }
    virtual ~Base() { delete caller; }
    Base(const Base& b) : caller(new Caller(*b.caller)) {}

    void init_caller();

    static void foo_callback(void*, int);
    static void bar_callback(void*, double);
    virtual void foo(int) = 0;
    virtual void bar(double) = 0;

    private:
    Base& operator =(const Base&);
    };

    #include <iostream>
    using std::cout;

    struct Derived : Base {
    virtual void foo(int a) { cout << "Derived::foo(" << a << ")\n"; }
    virtual void bar(double d) { cout << "Derived::bar(" << d <<
    ")\n"; }
    };

    void Base::foo_callback(void* ptr, int a) {
    Base *p = static_cast<Base*>(ptr);
    p->foo(a);
    }

    void Base::bar_callback(void* ptr, double d) {
    Base *p = static_cast<Base*>(ptr);
    p->bar(d);
    }

    void Base::init_caller() {
    caller->init_int_cb(foo_callback);
    caller->init_dbl_cb(bar_callback);

    caller->do_something();
    }

    int main() {
    Base *pb = new Derived;
    pb->init_caller();
    delete pb;
    }
    ---------------------------------------


    V
     
    Victor Bazarov, Mar 15, 2005
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Phil
    Replies:
    1
    Views:
    670
    llewelly
    Sep 16, 2003
  2. muser
    Replies:
    3
    Views:
    783
    Ron Natalie
    Sep 18, 2003
  3. Peter Goddard

    void pointers & void function pointers

    Peter Goddard, May 16, 2005, in forum: C Programming
    Replies:
    3
    Views:
    533
    Peter Goddard
    May 16, 2005
  4. n2xssvv g02gfr12930

    Smart pointers and member function pointers

    n2xssvv g02gfr12930, Nov 26, 2005, in forum: C++
    Replies:
    3
    Views:
    499
    n2xssvv g02gfr12930
    Nov 27, 2005
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    731
Loading...

Share This Page