Natknąłem się na ten dziwny fragment kodu, który dobrze się kompiluje:
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
return 0;
}
Dlaczego C ++ ma ten wskaźnik do niestatycznego elementu danych klasy? Jaki jest pożytek z tego dziwnego wskaźnika w prawdziwym kodzie?
Odpowiedzi:
Jest to „wskaźnik do elementu członkowskiego” - poniższy kod ilustruje jego użycie:
Co do tego , dlaczego chcesz to zrobić, to daje kolejny poziom pośrednictwa, który może rozwiązać niektóre trudne problemy. Ale szczerze mówiąc, nigdy nie musiałem używać ich we własnym kodzie.
Edycja: Nie mogę od razu przekonać się o przekonującym zastosowaniu wskaźników do danych członka. Wskaźnik do funkcji składowych może być używany w architekturach wtykowych, ale po raz kolejny stworzenie przykładu w małej przestrzeni mnie pokonuje. Oto moja najlepsza (nie przetestowana) próba - funkcja Apply, która wykonałaby pewne wstępne i końcowe przetwarzanie przed zastosowaniem funkcji członkowskiej wybranej przez użytkownika do obiektu:
Nawiasy wokół
c->*func
są konieczne, ponieważ->*
operator ma niższy priorytet niż operator wywołania funkcji.źródło
To najprostszy przykład, jaki mogę wymyślić, który przedstawia rzadkie przypadki, w których ta funkcja jest istotna:
Należy tutaj zwrócić uwagę na wskaźnik przekazywany do count_fruit. Dzięki temu nie musisz pisać osobnych funkcji count_apples i count_oranges.
źródło
&bowls.apples
i&bowls.oranges
?&bowl::apples
i&bowl::oranges
niczego nie wskazuje.&bowl::apples
i&bowl::oranges
nie wskazują na członków obiektu ; wskazują na członków klasy . Muszą być połączone ze wskaźnikiem do rzeczywistego obiektu, zanim wskażą na coś. Ta kombinacja została osiągnięta z->*
operatorem.Kolejną aplikacją są natrętne listy. Typ elementu może powiedzieć liście, jakie są jego następne / poprzednie wskaźniki. Tak więc lista nie używa zakodowanych nazw, ale nadal może korzystać z istniejących wskaźników:
źródło
next
.Oto rzeczywisty przykład, nad którym teraz pracuję, z systemów przetwarzania / kontroli sygnałów:
Załóżmy, że masz strukturę reprezentującą gromadzone dane:
Załóżmy teraz, że umieścisz je w wektorze:
Załóżmy teraz, że chcesz obliczyć jakąś funkcję (powiedzmy średnią) jednej ze zmiennych w zakresie próbek i chcesz uwzględnić to obliczenie średnie w funkcji. Wskaźnik do członka ułatwia:
Uwaga Zmodyfikowano 2016/08/05, aby uzyskać bardziej zwięzłe podejście do funkcji szablonu
I oczywiście możesz szablonować go, aby obliczyć średnią dla dowolnego iteratora do przodu i dowolnego typu wartości, który obsługuje dodawanie z samym sobą i dzielenie według size_t:
EDYCJA - Powyższy kod ma wpływ na wydajność
Należy zauważyć, jak wkrótce odkryłem, że powyższy kod ma poważne konsekwencje dla wydajności. Podsumowanie jest takie, że jeśli obliczasz statystyki podsumowujące na szeregach czasowych lub obliczasz FFT itp., Powinieneś przechowywać wartości dla każdej zmiennej w sposób ciągły w pamięci. W przeciwnym razie iteracja po serii spowoduje brak pamięci podręcznej dla każdej odzyskanej wartości.
Rozważ wydajność tego kodu:
W wielu architekturach jedno wystąpienie
Sample
wypełnia wiersz pamięci podręcznej. Tak więc przy każdej iteracji pętli jedna próbka zostanie wyciągnięta z pamięci do pamięci podręcznej. Zostaną wykorzystane 4 bajty z linii pamięci podręcznej, a resztę wyrzucone, a następna iteracja spowoduje kolejne pominięcie pamięci podręcznej, dostęp do pamięci i tak dalej.Znacznie lepiej to zrobić:
Teraz, gdy pierwsza wartość x jest ładowana z pamięci, kolejne trzy również zostaną załadowane do pamięci podręcznej (zakładając odpowiednie wyrównanie), co oznacza, że nie potrzebujesz żadnych wartości załadowanych dla następnych trzech iteracji.
Powyższy algorytm można nieco ulepszyć, stosując instrukcje SIMD np. W architekturach SSE2. Jednak działają one znacznie lepiej, jeśli wszystkie wartości są ciągłe w pamięci i można użyć jednej instrukcji, aby załadować razem cztery próbki (więcej w późniejszych wersjach SSE).
YMMV - zaprojektuj struktury danych zgodnie z algorytmem.
źródło
double Sample::*
część jest kluczowa!Możesz później uzyskać dostęp do tego członka w dowolnej instancji:
Pamiętaj, że potrzebujesz instancji, aby ją wywołać, więc nie działa ona jak delegat.
Jest używany rzadko, potrzebowałem go może raz lub dwa razy przez wszystkie lata.
Zwykle lepszym wyborem jest użycie interfejsu (tj. Czystej klasy bazowej w C ++).
źródło
IBM ma więcej dokumentacji na temat korzystania z tego. W skrócie, używasz wskaźnika jako przesunięcia w klasie. Nie możesz używać tych wskaźników oprócz klasy, do której się odnoszą, więc:
Wydaje się to trochę niejasne, ale jedną z możliwych aplikacji jest próba napisania kodu do deserializacji danych ogólnych na wiele różnych typów obiektów, a twój kod musi obsługiwać typy obiektów, o których absolutnie nic nie wie (na przykład twój kod jest w bibliotece, a obiekty, na które deserializujesz, zostały utworzone przez użytkownika Twojej biblioteki). Wskaźniki składowe dają ogólny, częściowo czytelny sposób odwoływania się do odsunięć poszczególnych składowych danych, bez konieczności uciekania się do typless void *, które można zastosować do struktur typu C.
źródło
Umożliwia wiązanie zmiennych i funkcji członka w jednolity sposób. Oto przykład z klasą samochodu. Bardziej powszechne użycie byłoby wiążące
std::pair::first
i::second
przy użyciu w algorytmach STL i doładowania na mapie.źródło
Możesz użyć tablicy wskaźnika do (jednorodnych) danych członka, aby włączyć podwójny interfejs o nazwie nazwany (iexdata) i indeks-tablica (tj. X [idx]).
źródło
union
typu pisowni w ten sposób nie jest dozwolone przez standard, ponieważ wywołuje wiele form nieokreślonego zachowania ... podczas gdy ta odpowiedź jest dobra.float *component[] = { &x, &y, &z }; return *component[idx];
tzn. Wskaźnik do komponentu wydaje się służyć jedynie celowi zaciemniającemu.Jednym ze sposobów jest to, że mam dwie implementacje, jak zrobić coś w klasie i chcę wybrać jedną w czasie wykonywania bez ciągłego przechodzenia przez instrukcję if, tj.
Oczywiście jest to praktycznie przydatne tylko wtedy, gdy uważasz, że kod jest wystarczająco wbijany, aby instrukcja if spowalniała wykonywanie zadań, np. gdzieś głęboko w żołądku jakiegoś intensywnego algorytmu. Nadal uważam, że jest bardziej elegancki niż stwierdzenie if, nawet w sytuacjach, w których nie ma praktycznego zastosowania, ale to tylko mój pomysł.
źródło
Algorithm
i dwóch klas pochodnych, np,AlgorithmA
aAlgorithmB
. W takim przypadku oba algorytmy są dobrze rozdzielone i zapewnione jest ich niezależne testowanie.Wskaźniki do klas nie są rzeczywistymi wskaźnikami; klasa jest konstrukcją logiczną i nie ma fizycznej pamięci w pamięci, jednak kiedy konstruujesz wskaźnik do członka klasy, daje on przesunięcie do obiektu klasy członka, w którym można go znaleźć; Daje to ważny wniosek: ponieważ elementy statyczne nie są powiązane z żadnym obiektem, więc wskaźnik do elementu NIE MOŻE wskazywać na element statyczny (dane lub funkcje), należy wziąć pod uwagę następujące kwestie :
Źródło: The Complete Reference C ++ - Herbert Schildt 4th Edition
źródło
Myślę, że powinieneś to zrobić tylko wtedy, gdy dane członka były dość duże (np. Obiekt innej dość potężnej klasy) i masz jakąś zewnętrzną procedurę, która działa tylko na odwołania do obiektów tej klasy. Nie chcesz kopiować obiektu członka, więc możesz go przekazać.
źródło
Oto przykład, w którym wskaźnik do elementów danych może być przydatny:
źródło
Załóżmy, że masz strukturę. Wewnątrz tej struktury znajduje się * jakaś nazwa * dwie zmienne tego samego typu, ale o innym znaczeniu
OK, powiedzmy teraz, że masz kilka
foo
s w pojemniku:Okej, teraz załóżmy, że ładujesz dane z oddzielnych źródeł, ale dane są prezentowane w ten sam sposób (np. Potrzebujesz tej samej metody analizy).
Możesz zrobić coś takiego:
W tym momencie wywołanie
readValues()
zwróci kontener z zestawieniem „input-a” i „input-b”; wszystkie klucze będą obecne, a foos z mają albo a albo b albo oba.źródło
Aby dodać kilka przykładów użycia odpowiedzi @ anon & @ Oktalist, oto świetny materiał do czytania na temat funkcji wskaźnik do członka i dane wskaźnik do członka.
https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-ptmf4.pdf
źródło