Вопрос заключается в следующем: рассмотрим этот кусок кода:
#include <iostream>class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
void function1(void (*function)(int, int))
{
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a();
function1(&test);
function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?
return 0;
}
Как я могу использовать a
«s aClass::test
в качестве аргумента function1
? Я застрял в этом.
Я хотел бы получить доступ к члену класса.
Нет ничего плохого в использовании указателей на функции. Однако указатели на нестатические функции-члены не похожи на обычные указатели на функции: функции-члены должны вызываться для объекта, который передается в качестве неявного аргумента функции. Подпись вашей функции-члена выше, таким образом,
void (aClass::*)(int, int)
а не тип, который вы пытаетесь использовать
void (*)(int, int)
Один подход может состоять в том, чтобы сделать функцию-член static
в этом случае он не требует вызова какого-либо объекта, и вы можете использовать его с типом void (*)(int, int)
,
Если вам нужен доступ к любому нестатическому члену вашего класса а также вам нужно придерживаться указателей функций, например, потому что функция является частью интерфейса C, ваш лучший вариант — всегда передавать void*
к вашей функции с помощью указателей на функции и вызова вашего члена через функцию пересылки, которая получает объект из void*
а затем вызывает функцию-член.
В правильном интерфейсе C ++ вы можете захотеть взглянуть на то, как ваша функция принимает шаблонный аргумент для объектов функции, использующих произвольные типы классов. Если использование шаблонного интерфейса нежелательно, вы должны использовать что-то вроде std::function<void(int, int)>
: вы можете создать для них подходящий вызываемый функциональный объект, например, используя std::bind()
,
Безопасные с точки зрения типов подходы с использованием аргумента шаблона для типа класса или подходящего std::function<...>
предпочтительнее, чем использование void*
интерфейс, поскольку они устраняют возможность ошибок из-за приведения к неправильному типу.
Чтобы уточнить, как использовать указатель на функцию для вызова функции-члена, вот пример:
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, 0);
foo object;
somefunction(&forwarder, &object);
}
@Pete Becker ответит хорошо, но вы также можете сделать это, не пройдя class
экземпляр как явный параметр function1
в C ++ 11:
#include <functional>
using namespace std::placeholders;
void function1(std::function<void(int, int)> fun)
{
fun(1, 1);
}
int main (int argc, const char * argv[])
{
...
aClass a;
auto fp = std::bind(&aClass::test, a, _1, _2);
function1(fp);
return 0;
}
Указатель на функцию-член отличается от указателя на функцию. Чтобы использовать функцию-член через указатель, вам нужен указатель на нее (очевидно) и объект, к которому она будет применена. Поэтому соответствующая версия function1
было бы
void function1(void (aClass::*function)(int, int), aClass& a) {
(a.*function)(1, 1);
}
и назвать это:
aClass a; // note: no parentheses; with parentheses it's a function declaration
function1(&aClass::test, a);
С 2011 года, если вы можете изменить function1
, сделайте так, вот так:
#include <functional>
#include <cstdio>
using namespace std;
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
template <typename Callable>
void function1(Callable f)
{
f(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main()
{
aClass obj;
// Free function
function1(&test);
// Bound member function
using namespace std::placeholders;
function1(std::bind(&aClass::aTest, obj, _1, _2));
// Lambda
function1([&](int a, int b) {
obj.aTest(a, b);
});
}
Обратите внимание, что я исправил определение вашего сломанного объекта (aClass a();
объявляет функцию).
Я задал похожий вопрос (C ++ openframeworks передает void от других классов) но ответ, который я нашел, был более понятным, поэтому вот объяснение будущих записей:
проще использовать std :: function как в:
void draw(int grid, std::function<void()> element)
а затем позвоните как:
grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));
или даже проще:
grid.draw(12, [&]{a.draw()});
где вы создаете лямбду, которая вызывает объект, захватывая его по ссылке
Вы можете перестать стучать головой Вот обертка для поддержки функции-члена существующий функции, принимающие в простом С функции в качестве аргументов. thread_local
директива является ключом здесь.
// Example program
#include <iostream>
#include <string>
using namespace std;
typedef int FooCooker_ (int);
// Existing function
extern "C" void cook_10_foo (FooCooker_ FooCooker) {
cout << "Cooking 10 Foo ..." << endl;
cout << "FooCooker:" << endl;
FooCooker (10);
}
struct Bar_ {
Bar_ (int Foo = 0) : Foo (Foo) {};
int cook (int Foo) {
cout << "This Bar got " << this->Foo << endl;
if (this->Foo >= Foo) {
this->Foo -= Foo;
cout << Foo << " cooked" << endl;
return Foo;
} else {
cout << "Can't cook " << Foo << endl;
return 0;
}
}
int Foo = 0;
};
// Each Bar_ object and a member function need to define
// their own wrapper with a global thread_local object ptr
// to be called as a plain C function.
thread_local static Bar_* BarPtr = NULL;
static int cook_in_Bar (int Foo) {
return BarPtr->cook (Foo);
}
thread_local static Bar_* Bar2Ptr = NULL;
static int cook_in_Bar2 (int Foo) {
return Bar2Ptr->cook (Foo);
}
int main () {
BarPtr = new Bar_ (20);
cook_10_foo (cook_in_Bar);
Bar2Ptr = new Bar_ (40);
cook_10_foo (cook_in_Bar2);
delete BarPtr;
delete Bar2Ptr;
return 0;
}
Пожалуйста, прокомментируйте любые проблемы с этим подходом.
Другие ответы не в состоянии назвать существующий гладкий C
функции: http://cpp.sh/8exun
Я сделал функцию-член статической, и все работает:
#include <iostream>
class aClass
{
public:
static void aTest(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
}
};
void function1(int a,int b,void function(int, int))
{
function(a, b);
}
void test(int a,int b)
{
printf("%d - %d = %d\n", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a;
function1(10,12,test);
function1(10,12,a.aTest); // <-- How should I point to a's aClass::test function?
getchar();return 0;
}