Ваша ошибка - использование внутреннего класса (вы пришли из Java?).
Я не знаю, чего, по вашему мнению, вы достигаете с помощью внутреннего класса, но это не сработает. Не используйте внутренние классы в C ++, если вы действительно не знаете, что он делает ( для внутренних классов, защищенные и закрытые члены внешних классов выглядят так, как если бы они были открытыми ).
Теперь, как решение вашей проблемы, я думаю, это зависит от используемой вами реализации (я однажды использовал Apache Xerces SAX, но я знаю, что Microsoft предлагает свою собственную реализацию SAX, и что должно быть много других альтернатив). итак ...)
Редактировать
После комментария я нашел следующий урок:
http://www.jamesh.id.au/articles/libxml-sax/libxml-sax.html
Я должен сказать, что, переходя с Java на C ++ и используя C API, вы набираетесь смелости ...
: - D
Если вы недостаточно знакомы с указателями на функции и C вообще, использование libxml2 будет проблемой. Убедитесь, что в конце вы поймете эти понятия ... Обратите внимание, что в C есть способ обработки данных, которые разработчики C ++, Java или C # связывают с this
. Способ C состоит в том, чтобы передать указатель на ваши данные (пользовательские данные) в функцию, и когда вызывается обратный вызов, он возвращает этот указатель, напечатанный как void *
. Затем вы должны вернуть его к нужному типу, и вуаля , у вас есть this
назад.
: -)
В любом случае, читая документацию, я вижу, что когда вы анализируете файл, вы вызываете следующую функцию C:
int xmlSAXUserParseFile( xmlSAXHandlerPtr sax,
void * user_data,
const char * filename);
user_data
- это та часть, которая вас интересует, потому что она позволяет вам иметь контекст. Итак, оборачивая эту функцию в класс C ++, вы можете получить что-то вроде:
// MySaxBase.hpp
class MySaxBase
{
public :
MySaxBase() ;
int parseFile(const std::string & p_filename) ;
virtual void startDocument() ;
virtual void endDocument() ;
private :
static void do_startDocument(void *p_user_data) ;
static void do_endDocument(void *p_user_data) ;
xmlSAXHandler m_sax ;
}
.
// MySaxBase.cpp
extern "C"
{
void do_startDocument(void *p_user_data)
{
// this static method will convert the p_user_data into
// the this pointer...
MySaxBase * saxBase = static_cast<MySaxBase *>(p_user_data) ;
// ...and call the right virtual method
saxBase->startDocument() ;
}
void do_endDocument(void *p_user_data)
{
// this static method will convert the p_user_data into
// the this pointer...
MySaxBase * saxBase = static_cast<MySaxBase *>(p_user_data) ;
// ...and call the right virtual method
saxBase->endDocument() ;
}
} // extern "C"
MySaxBase::MySaxBase()
{
// the m_sax structure must be set to zero to NULL all its
// pointers to functions
memset(&m_sax, 0, sizeof(xmlSAXHandler)) ;
// Now, we initialize some pointers to the static method we
// want to be called
this->m_sax.startDocument = do_startDocument ;
this->m_sax.endDocument = do_endDocument ;
}
int MySaxBase::parseFile(const std::string & p_filename)
{
// the important thing, here, is the this pointer, passed as
// a user_data parameter
return xmlSAXUserParseFile(&m_sax, this, p_filename.c_str()) ;
}
void MySaxBase::startDocument()
{
// The document started. Override this method to
// actually do something
}
void MySaxBase::endDocument()
{
// The document ended. Override this method to
// actually do something
}
Я не тестировал это, и я никогда не использовал libxml2, но я думаю, что код должен быть в порядке, и этого должно быть достаточно для продолжения самостоятельно: просто добавьте методы, которые вы хотите поддерживать, инициализируйте обработчик sax с соответствующими указателями на функции, и ваш класс будет завершен.
Методы MySaxBase::startDocument
и MySaxBase::endDocument
являются виртуальными для того, чтобы вы могли наследовать их от MySaxBase и затем переопределить эти методы.
Редактировать 2
Я воспроизведу здесь превосходный комментарий Стива Джессопа:
+ 1. Одно маленькое замечание - я не думаю, что static
функции-члены гарантированы стандартом C ++, чтобы иметь соглашение о связывании / вызове C, но использовать их в качестве обратного вызова из C API, это то, что им нужно. Я не знаю точно, какие реализации это имеет значение, но для безопасности do_startDocument
должна быть свободной функцией, объявленной с extern "C"
. По той же теме: Java-программист может не понимать, что вы должны убедиться, что функция не может выдать исключение (потому что в C их нет). Таким образом, вы обычно хотели бы видеть try/catch(...)
в функции оболочки. - Стив Джессоп
После этого и после прочтения Йоханнесом Шаубом - не менее отличного ответа от статического против внешнего "C" / "C ++" Йоханнеса Шауба, я изменил код так, чтобы сделать do_startDocument
и do_endDocument
настоящие функции C (то есть обернутые во внешний блок "C"). Обычно это не важно (я никогда не сталкивался с подобными проблемами), но лучше, чем потом сожалеть.