problem with function pointers

T

TheOne

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?
 
V

Victor Bazarov

TheOne said:
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;
}
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top