В моей программе C++ я должен назвать этот c API:
GConn* gnet_conn_new (const gchar *hostname,
gint port,
GConnFunc func);
где GConnFunc определяется как:
void (*GConnFunc) (GConn *conn);
Мой вопрос состоит в том, если я имею класс C++ и имею функцию членства как:
Class A {
public:
A();
void my_func (GConn* conn);
}
В моем A::A()
Конструктор, как я могу передать this->myfunc
кому: gnet_conn_new
как GConnFunc
параметр?
Спасибо.
Большинство API предоставляют аргумент «пользовательские данные» размером с указатель, который будет выглядеть следующим образом:
GConn* gnet_conn_new (const gchar *hostname,
gint port,
GConnFunc func,
void* user_data);
Это позволит вам передать экземпляр в user_data и пусть ваша функция C переадресуется функции-члену следующим образом:
void my_func(GConn *conn, void* user_data)
{
((MyClass*)user_data)->MyMemberFunc(conn);
}
Возможно, ваш API имеет где-то альтернативный или аналогичный параметр «пользовательских данных». В противном случае вы не сможете этого сделать без глобалов или статики.
Коротко, нельзя.
Длинный ответ:
Имея достаточную свободу действий со стороны API, который вам нужно вызвать, вы можете настроить функцию, которую вы просто регистрируете и вызываете в качестве посредника. Обычно функции обратного вызова позволяют включать дополнительные данные, которые передаются этой функции вместе с информацией, сгенерированной объектом, выполняющим обратный вызов. Обычно он называется что-то вроде client_data и имеет тип void * или long. В этом случае вы можете просто использовать эти данные, чтобы включить достаточно информации для вызова нужной функции в нужном вам экземпляре, например, добавив boost :: function <>.
Обратите внимание, что эта промежуточная функция, которая делегирует вашу функцию-член, может быть статическим членом или свободной функцией.
К сожалению, у вас нет такой возможности, поэтому ваша работа будет вдвойне трудной. Вам действительно нужен способ убедиться, что правильный экземпляр получил сообщение, и у вас нет возможности идентифицировать этот экземпляр по данным обратного вызова. Есть пара вариантов, которые могут или не могут сработать для вас:
убедитесь, что вы никогда не используете более одного экземпляра в качестве цели обратного вызова. Зарегистрируйте этот экземпляр с помощью синглтона или глобального некоторого вида, который отслеживает один экземпляр времени, на который следует ссылаться на события этого типа.
Зарегистрируйте столько экземпляров, сколько хотите, и просто убедитесь, что все они получают сообщение, а затем либо разобрались с ним, либо нет. Вы можете использовать здесь своего рода «цепочку ответственности», где цели предоставляется возможность обработать событие, а затем она возвращает что-то, позволяющее циклу знать, следует ли ему продолжить или прекратить.
В заключение, нет прямого способа делать то, что вы хотите, но могут быть ответы на получение того, что вам нужно, если вы рассмотрите варианты. Любая функция, используемая в качестве обратного вызова для функции C API, должна рассматриваться как указатель на функцию, а не как указатель на член любого типа ... и, к сожалению, не как функтор. C не знает, что делать с этими вещами, поэтому ваш обратный вызов должен быть бесплатной функцией или статическим членом.
Нестатическая функция-член в классе C ++ имеет скрытый параметр this. Если бы вы могли гипотетически преобразовать его в C, функция была бы преобразована как:
void A_my_func (A * const this, GConn* conn);
На самом деле нет способа выполнить это преобразование в вашем коде автоматически, хотя вы могли бы написать функцию-оболочку, используя прототип выше, и передать указатель на нее в функция C.
Обычный способ справиться с этим - передать либо бесплатную (не являющуюся членом) функцию, либо статическую функцию класса. Ни один из этих типов не имеет скрытого параметра.
Вы либо вам понадобится функция-оболочка для обработки этого, или вы можете сделать my_func статическим (при условии, что ему не нужен доступ к каким-либо переменным экземпляра).