Jaka jest ogólna idea delegata w C ++? Czym one są, jak są używane i do czego służą?
Chciałbym najpierw dowiedzieć się o nich w sposób „czarnej skrzynki”, ale trochę informacji o wnętrznościach tych rzeczy też byłoby świetne.
To nie jest C ++ w najczystszej lub najczystszej postaci, ale zauważam, że baza kodu, w której pracuję, ma ich pod dostatkiem. Mam nadzieję, że wystarczająco je zrozumiem, więc mogę ich po prostu użyć i nie będę musiał zagłębiać się w okropną okropność zagnieżdżonego szablonu.
Te dwa artykuły w The Code Project wyjaśniają, co mam na myśli, ale niezbyt zwięźle:
c++
delegates
delegation
SirYakalot
źródło
źródło
delegate
nie jest popularną nazwą w języku c ++. Powinieneś dodać trochę informacji do pytania, aby uwzględnić kontekst, w którym je przeczytałeś. Zwróć uwagę, że chociaż wzorzec może być wspólny, odpowiedzi mogą się różnić, jeśli mówisz o delegacie w ogóle lub w kontekście C ++ CLI lub dowolnej innej biblioteki, która ma określoną implementację delegata .Odpowiedzi:
Masz niesamowitą liczbę możliwości osiągnięcia delegatów w C ++. Oto te, które przyszły mi do głowy.
Opcja 1: funktory:
Obiekt funkcji można utworzyć poprzez implementację
operator()
Opcja 2: wyrażenia lambda ( C ++ 11 )
Opcja 3: wskaźniki funkcji
Opcja 4: wskaźnik do funkcji składowych (najszybsze rozwiązanie)
Zobacz Szybki delegat C ++ (w projekcie kodu ).
Opcja 5: std :: function
(lub
boost::function
jeśli Twoja standardowa biblioteka go nie obsługuje). Jest wolniejszy, ale jest najbardziej elastyczny.Opcja 6: Wiązanie (przy użyciu std :: bind )
Pozwala na ustawienie niektórych parametrów z wyprzedzeniem, na przykład wygodne wywołanie funkcji składowej.
Opcja 7: szablony
Akceptuj wszystko, o ile pasuje do listy argumentów.
źródło
std::bind
, i oba naprawdę robią to samo, z wyjątkiem tego, że lambdy nie są polimorficzne w tym sensie, że mogą akceptować różne typy argumentów.binding
na mojej liście). Nie można tego osiągnąć za pomocą wskaźników funkcji.Delegat to klasa, która otacza wskaźnik lub odwołanie do instancji obiektu, metodę składową klasy tego obiektu, która ma zostać wywołana w tym wystąpieniu obiektu, i udostępnia metodę wyzwalającą to wywołanie.
Oto przykład:
źródło
Execute()
wyzwalania wywołania funkcji na obiekcie zawijanym przez delegata.Potrzeba implementacji delegatów C ++ jest długotrwałym wstydem dla społeczności C ++. Każdy programista C ++ chciałby je mieć, więc ostatecznie używają ich pomimo faktów, że:
std::function()
używa operacji na stercie (i jest poza zasięgiem poważnego programowania osadzonego).Wszystkie inne implementacje idą na ustępstwa w kierunku przenośności lub zgodności ze standardami w większym lub mniejszym stopniu (prosimy o sprawdzenie, sprawdzając różne implementacje delegatów tutaj i na projekcie kodu). Nie widziałem jeszcze implementacji, która nie używa dzikich reinterpret_casts, "prototypów" zagnieżdżonych klas, które, mam nadzieję, wytwarzają wskaźniki funkcji o takim samym rozmiarze, jak ten przekazany przez użytkownika, sztuczki kompilatora, takie jak najpierw deklaracja w przód, a następnie typedef, a następnie deklaracja ponownie, tym razem dziedziczenie z innej klasy lub podobnych podejrzanych technik. Chociaż jest to wielkie osiągnięcie dla osób wdrażających, które to stworzyły, wciąż jest smutnym świadectwem ewolucji C ++.
Rzadko kiedy wskazuje się, że obecnie ponad 3 standardowe wersje C ++ delegatów nie zostały odpowiednio zaadresowane. (Lub brak funkcji językowych, które pozwalają na proste implementacje delegatów).
Ze sposobem, w jaki funkcje lambda C ++ 11 są definiowane przez standard (każda lambda ma anonimowy, inny typ), sytuacja poprawiła się tylko w niektórych przypadkach użycia. Jednak w przypadku użycia delegatów w interfejsach API bibliotek (DLL) same lambdy nadal nie są użyteczne. Typową techniką jest tutaj najpierw spakowanie lambdy do funkcji std ::, a następnie przekazanie jej przez interfejs API.
źródło
std::function
nie zawsze dynamicznie alokujeMówiąc najprościej, delegat zapewnia funkcjonalność opisującą, jak powinien działać wskaźnik funkcji. Istnieje wiele ograniczeń wskaźników funkcji w C ++. Delegat używa zakulisowych szablonów, aby utworzyć obiekt typu wskaźnika funkcji klasy szablonu, który działa tak, jak chcesz.
tj. - możesz ustawić je tak, aby wskazywały na daną funkcję i możesz je przekazywać i wywoływać kiedykolwiek i gdziekolwiek chcesz.
Oto kilka bardzo dobrych przykładów:
źródło
Opcją dla delegatów w C ++, która nie została tutaj inaczej wymieniona, jest zrobienie tego w stylu C przy użyciu funkcji ptr i argumentu kontekstu. Jest to prawdopodobnie ten sam wzorzec, którego wielu ludzi zadających to pytanie stara się uniknąć. Ale wzorzec jest przenośny, wydajny i można go używać w kodzie osadzonym i jądrze.
źródło
Odpowiednik środowiska wykonawczego systemu Windows obiektu funkcji w standardowym C ++. Można użyć całej funkcji jako parametru (właściwie jest to wskaźnik funkcji). Jest używany głównie w połączeniu z wydarzeniami. Delegat reprezentuje kontrakt, który w znacznym stopniu spełniają programy obsługi zdarzeń. Ułatwia to, jak może działać wskaźnik funkcji.
źródło