Jak uzyskać wskaźnik funkcji dla funkcji składowej klasy, a następnie wywołać tę funkcję składową z określonym obiektem? Chciałbym napisać:
class Dog : Animal
{
Dog ();
void bark ();
}
…
Dog* pDog = new Dog ();
BarkFunction pBark = &Dog::bark;
(*pBark) (pDog);
…
Ponadto, jeśli to możliwe, chciałbym również wywołać konstruktor za pomocą wskaźnika:
NewAnimalFunction pNew = &Dog::Dog;
Animal* pAnimal = (*pNew)();
Czy jest to możliwe, a jeśli tak, jaki jest preferowany sposób, aby to zrobić?
c++
function-pointers
class-method
Tony the Pony
źródło
źródło
Dog dog;
) jest bardziej prawdopodobny.Odpowiedzi:
Przeczytaj to, aby uzyskać szczegółowe informacje:
źródło
*this.*pt2Member
zadziała.*
ma wyższy priorytet nad.*
… Osobiście nadal bym napisałthis->*pt2Member
, że to jeden operator mniej.pt2ConstMember
doNULL
?(object.*method_pointer)
, dlatego chcemy,*
aby miały one większy priorytet.this
jest używane tylko do zademonstrowania, że cokolwiek zastosujesz,.*
powinno być wskaźnikiem do instancji (pod) klasy. Jest to jednak dla mnie nowa składnia, zgaduję tylko na podstawie innych odpowiedzi i zasobów połączonych tutaj. Proponuję edycję, aby było to bardziej zrozumiałe.Najłatwiej jest zacząć od pliku
typedef
. W przypadku funkcji składowej dodaj nazwę klasy w deklaracji typu:Następnie, aby wywołać metodę, użyj
->*
operatora:Nie wierzę, że można pracować z takimi konstruktorami - lekarze i lekarze są wyjątkowi. Normalnym sposobem osiągnięcia tego typu rzeczy byłoby użycie metody fabrycznej, która jest po prostu statyczną funkcją, która wywołuje konstruktor za Ciebie. Zobacz poniższy kod jako przykład.
Zmodyfikowałem Twój kod, aby zasadniczo robił to, co opisujesz. Poniżej znajdują się zastrzeżenia.
Teraz, chociaż normalnie można użyć a
Dog*
zamiastAnimal*
podziękowania dzięki magii polimorfizmu, typ wskaźnika funkcji nie jest zgodny z regułami wyszukiwania hierarchii klas. Dlatego wskaźnik metody Animal nie jest zgodny ze wskaźnikiem metody Dog, innymi słowy nie można przypisaćDog* (*)()
zmiennej typu a do zmiennej typuAnimal* (*)()
.Metoda statyczna
newDog
to prosty przykład fabryki, która po prostu tworzy i zwraca nowe instancje. Będąc funkcją statyczną, ma zwykłątypedef
(bez kwalifikatora klasy).Po udzieleniu odpowiedzi na powyższe pytanie zastanawiam się, czy nie ma lepszego sposobu na osiągnięcie tego, czego potrzebujesz. Jest kilka konkretnych scenariuszy, w których można by to zrobić, ale może się okazać, że istnieją inne wzorce, które lepiej sprawdzają się w przypadku Twojego problemu. Jeśli bardziej ogólnie opiszesz to, co próbujesz osiągnąć, umysł roju może okazać się jeszcze bardziej przydatny!
W związku z powyższym bez wątpienia biblioteka Boost bind i inne powiązane moduły będą bardzo przydatne.
źródło
->*
, ale teraz mam nadzieję, że nigdy nie będę tego potrzebować :)Nie sądzę, aby ktokolwiek tutaj wyjaśnił, że jednym z problemów jest to, że potrzebujesz „ wskaźników do elementów członkowskich ”, a nie zwykłych wskaźników funkcji.
Wskaźniki składowe do funkcji nie są po prostu wskaźnikami funkcji. W terminologii implementacji kompilator nie może użyć prostego adresu funkcji, ponieważ generalnie nie znasz adresu do wywołania, dopóki nie wiesz, do którego obiektu należy wyłuskać (pomyśl o funkcjach wirtualnych). Oczywiście musisz znać obiekt, aby podać
this
ukryty parametr.Powiedziałem, że ich potrzebujesz, teraz powiem, że naprawdę musisz ich unikać. Poważnie, wskazówki dla członków są uciążliwe. O wiele rozsądniej jest spojrzeć na wzorce projektowe zorientowane obiektowo, które osiągają ten sam cel, lub użyć
boost::function
czegoś, co wspomniano powyżej - to znaczy zakładając, że dokonasz tego wyboru.Jeśli dostarczasz ten wskaźnik funkcji do istniejącego kodu, więc naprawdę potrzebujesz prostego wskaźnika funkcji, powinieneś napisać funkcję jako statyczny element członkowski klasy. Statyczna funkcja członkowska nie rozumie
this
, więc musisz przekazać obiekt jako jawny parametr. Kiedyś istniał nie tak niezwykły idiom do pracy ze starym kodem C, który wymaga wskaźników funkcjiPonieważ
myfunction
jest to tak naprawdę zwykła funkcja (pomijając kwestie zakresu), wskaźnik funkcji można znaleźć w normalnym języku C.EDYCJA - ten rodzaj metody nazywany jest „metodą klasową” lub „statyczną funkcją składową”. Główną różnicą w stosunku do funkcji niebędącej składową jest to, że jeśli odwołujesz się do niej spoza klasy, musisz określić zakres za pomocą
::
operatora rozpoznawania zakresu. Na przykład, aby uzyskać wskaźnik funkcji, użyj&myclass::myfunction
i, aby wywołać użyciemyclass::myfunction (arg);
.Tego rodzaju rzeczy są dość powszechne w przypadku używania starych interfejsów API Win32, które pierwotnie były zaprojektowane dla języka C, a nie C ++. Oczywiście w takim przypadku parametr jest zwykle LPARAM lub podobny, a nie wskaźnik, i potrzebne jest pewne rzutowanie.
źródło
źródło
Minimalny działający przykład
main.cpp
Skompiluj i uruchom:
Testowane w Ubuntu 18.04.
Nie możesz zmienić kolejności nawiasów ani ich pominąć. Następujące elementy nie działają:
GCC 9.2 nie powiedzie się z:
Standard C ++ 11
.*
i->*
są pojedynczymi operatorami wprowadzonymi w tym celu w C ++ i nie występują w C.Wersja robocza standardu C ++ 11 N3337 :
.*
i->*
.źródło
Przyszedłem tutaj, aby dowiedzieć się, jak utworzyć wskaźnik funkcji (nie wskaźnik metody) na podstawie metody, ale żadna z odpowiedzi tutaj nie zapewnia rozwiązania. Oto co wymyśliłem:
Więc dla twojego przykładu zrobiłbyś teraz:
Edycja:
Używając C ++ 17, istnieje jeszcze lepsze rozwiązanie:
które mogą być używane bezpośrednio bez makra:
W przypadku metod z modyfikatorami, takimi jak
const
Ty, możesz potrzebować dodatkowych specjalizacji, takich jak:źródło
Powodem, dla którego nie można używać wskaźników funkcji do wywoływania funkcji składowych, jest to, że zwykłe wskaźniki do funkcji są zwykle po prostu adresami pamięci funkcji.
Aby wywołać funkcję członkowską, musisz wiedzieć dwie rzeczy:
Zwykłe wskaźniki funkcji nie mogą przechowywać obu. Wskaźniki funkcji składowej C ++ są używane do przechowywania a), dlatego należy jawnie określić instancję podczas wywoływania wskaźnika funkcji składowej.
źródło
Wskaźnik funkcji do elementu klasy to problem, który naprawdę pasuje do używania funkcji boost :: function. Mały przykład:
źródło
Aby utworzyć nowy obiekt, możesz użyć umieszczania nowego obiektu, jak wspomniano powyżej, lub pozwolić klasie zaimplementować metodę clone (), która tworzy kopię obiektu. Następnie możesz wywołać tę metodę klonowania za pomocą wskaźnika funkcji składowej, jak wyjaśniono powyżej, aby utworzyć nowe wystąpienia obiektu. Zaletą clone jest to, że czasami możesz pracować ze wskaźnikiem do klasy bazowej, w której nie znasz typu obiektu. W takim przypadku metoda clone () może być łatwiejsza w użyciu. Ponadto clone () pozwoli ci skopiować stan obiektu, jeśli tego chcesz.
źródło
Zrobiłem to za pomocą std :: function i std :: bind ..
Napisałem tę klasę EventManager, która przechowuje wektor programów obsługi w unordered_map, która mapuje typy zdarzeń (które są po prostu const unsigned int, mam ich duże wyliczenie w zakresie przestrzeni nazw) do wektora programów obsługi dla tego typu zdarzenia.
W mojej klasie EventManagerTests konfiguruję procedurę obsługi zdarzeń, taką jak ta:
Oto funkcja AddEventListener:
Oto definicja typu EventHandler:
Następnie w EventManagerTests :: RaiseEvent robię to:
Oto kod dla EventManager :: RaiseEvent:
To działa. Otrzymuję wezwanie w EventManagerTests :: OnKeyDown. Muszę usunąć wektory, przyjść na czas czyszczenia, ale kiedy to zrobię, nie ma wycieków. Podniesienie zdarzenia zajmuje na moim komputerze około 5 mikrosekund, czyli około 2008 roku. Nie do końca superszybkie, ale. W porządku, o ile wiem o tym i nie używam go w bardzo gorącym kodzie.
Chciałbym to przyspieszyć, zwijając własne std :: function i std :: bind i być może używając tablicy tablic zamiast unordered_map wektorów, ale nie do końca wymyśliłem, jak przechowywać funkcję składową wskaźnik i wywołaj go z kodu, który nic nie wie o wywoływanej klasie. Odpowiedź rzęs wygląda bardzo interesująco.
źródło