"TheOne" <su************ ****@gmail.com> wrote...
I have two classes:
class OntologyParser
{
...
protected:
virtual void startElement(vo id *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(co nst string& fname);
.....
};
This class is a base class for
class ProtegeOntology Parser : public OntologyParser
{
public:
inline ProtegeOntology Parser(const string& strFileName)
{
initXMLParse(st rFileName);
}
};
I am using G++ on RedHat 9.0 Linux with Expat library.
The initXMLParse function is common to all (here just
ProtegeOntology Parser) 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(c onst string& fname)
{
char buffer[BUFSIZ];
int len;
int done;
int depth = 0;
//Get the Parser
XML_Parser parser = XML_ParserCreat e(NULL);
//User Data Handler
XML_SetUserData (parser, &depth);
//Element Level Handler
XML_SetElementH andler(parser, startElement, endElement);
//Set What to do with the data
XML_SetCharacte rDataHandler( 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_callba ck)(void*,doubl e);
void* ptr;
void init_ptr(void* p) { ptr = p; }
void init_int_cb(voi d (*icb)(void*,in t)) { int_callback = icb; }
void init_dbl_cb(voi d (*dcb)(void*,do uble)) { double_callback =
dcb; }
void do_something() {
int_callback(pt r, 666);
double_callback (ptr, 3.1415926);
int_callback(pt r, 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.calle r)) {}
void init_caller();
static void foo_callback(vo id*, int);
static void bar_callback(vo id*, 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::f oo(" << a << ")\n"; }
virtual void bar(double d) { cout << "Derived::b ar(" << d <<
")\n"; }
};
void Base::foo_callb ack(void* ptr, int a) {
Base *p = static_cast<Bas e*>(ptr);
p->foo(a);
}
void Base::bar_callb ack(void* ptr, double d) {
Base *p = static_cast<Bas e*>(ptr);
p->bar(d);
}
void Base::init_call er() {
caller->init_int_cb(fo o_callback);
caller->init_dbl_cb(ba r_callback);
caller->do_something() ;
}
int main() {
Base *pb = new Derived;
pb->init_caller( );
delete pb;
}
---------------------------------------
V