Pytanie jest następujące: rozważ ten fragment kodu:
#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;
}
Jak mogę korzystać z a
„s aClass::test
jako argument function1
? Utknąłem w tym.
Chciałbym uzyskać dostęp do członka klasy.
c++
arguments
parameter-passing
function-pointers
pointer-to-member
Jorge Leitao
źródło
źródło
Odpowiedzi:
Nie ma nic złego w używaniu wskaźników funkcji. Jednak wskaźniki do niestatycznych funkcji składowych nie są podobne do zwykłych wskaźników do funkcji: funkcje składowe muszą być wywoływane w obiekcie, który jest przekazywany jako niejawny argument funkcji. Zatem podpis twojej funkcji członkowskiej powyżej to
zamiast typu, którego próbujesz użyć
Jedno podejście mogłoby polegać na utworzeniu funkcji składowej,
static
w którym to przypadku nie wymaga ona wywołania żadnego obiektu i można jej użyć z typemvoid (*)(int, int)
.Jeśli potrzebujesz dostępu do dowolnego niestatycznego elementu członkowskiego swojej klasy i musisz trzymać się wskaźników do funkcji, np. Ponieważ funkcja jest częścią interfejsu C, najlepszą opcją jest zawsze przekazywanie
void*
do funkcji a, przyjmując wskaźniki do funkcji i wywołując Twój element członkowski za pośrednictwem funkcji przekazującej, która uzyskuje obiekt z,void*
a następnie wywołuje funkcję składową.W odpowiednim interfejsie C ++ możesz rzucić okiem na to, aby Twoja funkcja pobierała argument oparty na szablonie dla obiektów funkcji, aby używały dowolnych typów klas. Jeśli używanie szablonu interfejsu jest niepożądane, powinieneś użyć czegoś takiego
std::function<void(int, int)>
: możesz utworzyć dla nich odpowiednio wywoływalny obiekt funkcji, npstd::bind()
. Using .Podejścia z bezpiecznym typem przy użyciu argumentu szablonu dla typu klasy lub odpowiedniego
std::function<...>
są lepsze niż użycievoid*
interfejsu, ponieważ eliminują potencjalne błędy wynikające z rzutowania na niewłaściwy typ.Aby wyjaśnić, jak używać wskaźnika funkcji do wywoływania funkcji składowej, oto przykład:
źródło
void*
, co oznacza, że możesz uzyskać bardzo nieprzyjemne błędy, ponieważ nie jest już wpisywana jako sprawdzona.Odpowiedź @Pete Becker jest w porządku, ale możesz to również zrobić bez przekazywania
class
instancji jako jawnego parametrufunction1
w C ++ 11:źródło
void function1(std::function<void(int, int)>)
poprawne?void function1(std::function<void(int, int)> functionToCall)
a potemfunctionToCall(1,1);
. Próbowałem edytować odpowiedź, ale ktoś odrzucił ją jako bezsensowną z jakiegoś powodu. Zobaczymy, czy w pewnym momencie zostanie on przegłosowany.Wskaźnik do funkcji składowej różni się od wskaźnika do funkcji. Aby użyć funkcji składowej za pośrednictwem wskaźnika, potrzebujesz wskaźnika do niej (oczywiście) i obiektu, do którego chcesz ją zastosować. Więc odpowiednia wersja
function1
będziei nazwać to:
źródło
function
wvoid (aClass::*function)(int, int)
był typem, ponieważ jest to typ wtypedef void (aClass::*function)(int, int)
.typedef int X;
definiuje typ;int X;
tworzy obiekt.Od 2011, jeśli możesz to zmienić
function1
, zrób to w ten sposób:( demo na żywo )
Zauważ również, że poprawiłem twoją zepsutą definicję obiektu (
aClass a();
deklaruje funkcję).źródło
Zadałem podobne pytanie ( otwarte ramy C ++ przechodzą nieważne z innych klas ), ale odpowiedź, którą znalazłem, była jaśniejsza, więc tutaj wyjaśnienie dla przyszłych rekordów:
łatwiej jest użyć funkcji std :: jak w:
a następnie zadzwoń jako:
lub jeszcze łatwiej:
gdzie tworzysz lambdę, która wywołuje obiekt przechwytujący go przez odniesienie
źródło
std::function
indraw
zamiast kopiowania go przy każdym wywołaniu.Zrobiłem element członkowski jako statyczny i wszystko działa:
źródło
Nie jestem pewien, dlaczego pominięto to niezwykle proste rozwiązanie:
Wynik:
źródło
Jeśli faktycznie nie trzeba korzystać z instancji
a
(czyli można je statyczne jak @mathengineer „s odpowiedzi ) można po prostu przejść w lambda non-capture. (które rozpadają się na wskaźnik funkcji)Wandbox
uwaga: jeśli
aClass
jest kosztowna w budowie lub ma efekt uboczny, może to nie być dobry sposób.źródło
Możesz teraz przestać walić głową. Oto opakowanie dla funkcji składowej do obsługi istniejących funkcji przyjmujących zwykłe funkcje C jako argumenty.
thread_local
Dyrektywa jest tutaj kluczowa.http://cpp.sh/9jhk3
Prosimy o skomentowanie wszelkich problemów związanych z tym podejściem.
Inne odpowiedzi nie wywołują istniejących zwykłych
C
funkcji: http://cpp.sh/8exunźródło
C
funkcje jako argumenty.