C++ имеет ограниченную возможность использовать функции указателя на элемент. Мне нужно что-то, что позволит мне динамически выбирать функцию-функцию обратного вызова, чтобы использовать шаблон Visitor метода XMLNode::Accept(XMLVisitor *visitor)
из библиотеки TinyXML2.Как работать с ограничением функции указателя на объект C++
Чтобы использовать XMLNode::Accept()
, я должен назвать его классом, который реализует интерфейс XMLVisitor
. Следовательно:
typedef bool (*Callback)(string, string);
class MyVisitor : public tinyxml2::XMLVisitor {
public:
bool VisitExit(const tinyxml2::XMLElement &e) {
callback(e.Name(), e.GetText());
}
Callback callback;
}
Это прекрасно работает, если мой абонент не является объектом, который хочет использовать один из своих собственных методов в качестве функции обратного вызова (так, что он может получить доступ к переменным класса). Например, это работает:
bool myCallBackFunc(string e, string v) {
cout << "Element " << e << " has value " << v << endl;
return true;
}
int main(...) {
tinyxml2::XMLDocument doc;
doc.LoadFile("somefile.xml");
MyVisitor visit;
visit.callback = myCallBackFunc;
doc.Accept(&visit);
}
Однако в моем случае использования, синтаксический анализ делается внутри метода в классе. У меня есть несколько приложений, которые имеют похожие, но уникальные классы. Я бы хотел использовать только один общий класс MyVisitor
, вместо того, чтобы класс посетителя имел уникальное знание внутренних компонентов каждого класса, который будет его называть.
Таким образом, было бы удобно, если бы функция обратного вызова была методом в каждом вызывающем классе, чтобы я мог влиять на внутреннее состояние объекта, созданного из этого вызывающего класса.
Верхний уровень: У меня есть 5 серверных приложений, которые говорят с 5 различными торговыми партнерами, которые все отправляют ответы XML, но каждый из них достаточно различен, что каждое приложение сервера имеет класс, уникальный для этого торгового партнера. Я стараюсь следить за хорошим дизайном OO и DRY и избегать дополнительных классов, обладающих уникальными знаниями, в то же время выполняющих в основном ту же работу.
Вот метод класса, я хочу, чтобы Accept()
перезвонить.
ServiceClass::changeState(string elem, string value) {
// Logic which sets member vars based on element found and its value.
}
Вот метод класса, который будет вызывать Accept()
ходить XML:
ServiceClass::processResponse(string xml) {
// Parse XML and do something only if certain elements present.
tinyxml2::XMLDocument doc;
doc.Parse(xml.c_str(), xml.length());
MyVisitor visit;
visit.callback = &changeState; // ERROR. Does not work.
visit.callback = &ServiceClass::changeState; // ERROR. Does not work.
doc.Accept(&visit);
}
Что простой способ получить то, что я хочу? Я могу представить себе больше классов с производными классами, уникальными для каждой ситуации, но это кажется чрезвычайно многословным и неуклюжим.
Примечание. В интересах краткости мой примерный код выше не имеет проверки ошибок, не имеет нулевой проверки и может даже иметь незначительные ошибки (например, обработка const char *
в виде строки ;-).
Вы пробовали std :: bind? –