Как функция обратного вызова может изменять член объекта? [Дубликат]

Я думаю, что папка с ресурсами общедоступна, вы можете получить к ней доступ непосредственно в браузере

http: // localhost: 4020 / assets /

в отличие от других приватных папок, отбросьте свой json-файл в папку с ресурсами

51
задан btlog 17 May 2016 в 20:21
поделиться

8 ответов

Как вы теперь показали, ваша функция init принимает не-членную функцию. так что сделайте это так:

static void Callback(int other_arg, void * this_pointer) {
    CLoggersInfra * self = static_cast<CLoggersInfra*>(this_pointer);
    self->RedundencyManagerCallBack(other_arg);
}

и вызовите Init с

m_cRedundencyManager->Init(&CLoggersInfra::Callback, this);

Это работает, потому что указатель функции на статическую функцию-член не является указателем на функцию-член и может таким образом обрабатываться как указатель на свободную функцию.

40
ответ дан Johannes Schaub - litb 17 August 2018 в 16:22
поделиться
91
ответ дан Community 17 August 2018 в 16:22
поделиться

Доступна ли функция m_cRedundencyManager для использования функций-членов? Большинство обратных вызовов настроены на использование регулярных функций или статических функций-членов.

Обновление: Объявление функции, которое вы указали, показывает, что m_cRedundencyManager ожидает, что функция вида: void yourCallbackFunction(int, void *). Поэтому функции-члены неприемлемы как обратные вызовы в этом случае. Статическая функция-член может работать, но если это неприемлемо в вашем случае, будет работать и следующий код. Обратите внимание, что он использует злое действие из void *.


// in your CLoggersInfra constructor:
m_cRedundencyManager->Init(myRedundencyManagerCallBackHandler, this);

// in your CLoggersInfra header:
void myRedundencyManagerCallBackHandler(int i, void * CLoggersInfraPtr);

// in your CLoggersInfra source file:
void myRedundencyManagerCallBackHandler(int i, void * CLoggersInfraPtr)
{
    ((CLoggersInfra *)CLoggersInfraPtr)->RedundencyManagerCallBack(i);
}
3
ответ дан e.James 17 August 2018 в 16:22
поделиться

Указатель на функцию-член класса не совпадает с указателем на функцию. Член класса принимает неявный дополнительный аргумент (указатель этого ) и использует другое соглашение о вызове.

Если ваш API ожидает функцию обратного вызова без ответа, это то, что вам нужно пройти к нему.

2
ответ дан jalf 17 August 2018 в 16:22
поделиться

Какой аргумент делает Init? Какое новое сообщение об ошибке?

Указатели метода на C ++ немного сложны в использовании. Помимо самого указателя метода, вам также необходимо указать указатель экземпляра (в вашем случае this). Может быть, Init ожидает, что это будет отдельный аргумент?

3
ответ дан Konrad Rudolph 17 August 2018 в 16:22
поделиться

Я вижу, что init имеет следующее переопределение:

Init (CALLBACK_FUNC_EX callback_func, void * callback_parm)

, где CALLBACK_FUNC_EX is typedef void (* CALLBACK_FUNC_EX) (int, void *); [/ д2]

1
ответ дан ofer 17 August 2018 в 16:22
поделиться

Этот вопрос и ответ из C ++ FAQ Lite охватывает ваш вопрос и соображения, связанные с ответом, довольно красиво, я думаю. Короткие фрагменты с веб-страницы, с которой я связан:

Do not.

Поскольку функция-член бессмысленна, если объект не вызывает его, вы не можете этого сделать (если система X Window была переписана на C ++, она, вероятно, передавала бы ссылки на объекты, а не только указатели на функции, естественно, объекты воплотили бы требуемую функцию и, вероятно, намного больше).

0
ответ дан Onorio Catenacci 17 August 2018 в 16:22
поделиться
  • 1
    Ссылка теперь isocpp.org/wiki/faq/pointers-to-members#memfnptr-vs-fnptr ; похоже, теперь он говорит «Не делай». Вот почему ссылки только для ответов не являются хорошими. – Limited Atonement 12 January 2016 в 20:45
  • 2
    Не стесняйтесь редактировать мой восьмилетний ответ :-) – Onorio Catenacci 12 January 2016 в 23:06
  • 3
    О да ... duh :-) – Limited Atonement 13 January 2016 в 16:55
  • 4
    Я изменил ответ @LimitedAtonement. Спасибо за указание на это. Вы полностью правы, что ссылки только ответы низкого качества ответов. Но мы не знали этого еще в 2008 году: -P – Onorio Catenacci 13 January 2016 в 17:04

Этот ответ является ответом на комментарий выше и не работает с VisualStudio 2008, но должен быть предпочтительнее с более поздними компиляторами.


Между тем вам больше не нужно использовать указатель void и нет необходимости в усилении, так как доступны std::bind и std::function . Преимущество одного (по сравнению с указателями void) - это безопасность типа, поскольку тип возврата и аргументы явно указаны с помощью std::function:

// std::function<return_type(list of argument_type(s))>
void Init(std::function<void(void)> f);

Затем вы можете создать функцию указатель с std::bind и передать его Init:

auto cLoggersInfraInstance = CLoggersInfra();
auto callback = std::bind(&CLoggersInfra::RedundencyManagerCallBack, cLoggersInfraInstance);
Init(callback);

Полный пример для использования std::bind с членами, статическими членами и не-членными функциями:

#include <functional>
#include <iostream>
#include <string>

class RedundencyManager // incl. Typo ;-)
{
public:
    // std::function<return_type(list of argument_type(s))>
    std::string Init(std::function<std::string(void)> f) 
    {
        return f();
    }
};

class CLoggersInfra
{
private:
    std::string member = "Hello from non static member callback!";

public:
    static std::string RedundencyManagerCallBack()
    {
        return "Hello from static member callback!";
    }

    std::string NonStaticRedundencyManagerCallBack()
    {
        return member;
    }
};

std::string NonMemberCallBack()
{
    return "Hello from non member function!";
}

int main()
{
    auto instance = RedundencyManager();

    auto callback1 = std::bind(&NonMemberCallBack);
    std::cout << instance.Init(callback1) << "\n";

    // Similar to non member function.
    auto callback2 = std::bind(&CLoggersInfra::RedundencyManagerCallBack);
    std::cout << instance.Init(callback2) << "\n";

    // Class instance is passed to std::bind as second argument.
    // (heed that I call the constructor of CLoggersInfra)
    auto callback3 = std::bind(&CLoggersInfra::NonStaticRedundencyManagerCallBack,
                               CLoggersInfra()); 
    std::cout << instance.Init(callback3) << "\n";
}

Возможный выход:

Hello from non member function!
Hello from static member callback!
Hello from non static member callback!

Кроме того, используя std::placeholders , вы можете динамически передавать аргументы для обратного вызова (например, это позволяет использовать return f("MyString"); в Init, если f имеет строковый параметр).

4
ответ дан Roi Danton 17 August 2018 в 16:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: