Odpowiedzi:
Następujące dwa wyrażenia są równoważne:
a->b
(*a).b
(z zastrzeżeniem przeciążenia operatora, jak wspomina Konrad, ale to nietypowe).
a[0].b
zamiast (*a).b
. Ale nie byłby tak odpowiednio skonstruowany.
a->b
jest generalnie synonimem (*a).b
. Nawiasy są tutaj konieczne ze względu na siłę wiązania operatorów, *
a .
: *a.b
nie zadziała, ponieważ .
wiąże się silniej i jest wykonywany jako pierwszy. Jest to zatem równoważne z *(a.b)
.
Uważaj jednak na przeciążenie: ponieważ oba ->
i *
mogą być przeciążone, ich znaczenie może się drastycznie różnić.
binding strength
to znaczy pierwszeństwo operatora? jeśli nie, jaka jest różnica między nimi?
Język C ++ - definiuje operator strzałki ( ->
) jako synonim do wyłuskiwania wskaźnika, a następnie używa operatora .
-operatora na tym adresie.
Na przykład:
Jeśli masz obiekt anObject
i wskaźnik aPointer
:
SomeClass anObject = new SomeClass();
SomeClass *aPointer = &anObject;
Aby móc użyć jednej z metod obiektów, wyłuskujemy wskaźnik i wykonujemy wywołanie metody na tym adresie:
(*aPointer).method();
Które można zapisać za pomocą operatora strzałki:
aPointer->method();
Głównym powodem istnienia operatora strzałki jest to, że skraca on wpisywanie bardzo powszechnego zadania, a także dość łatwo zapomnieć o nawiasach wokół dereferencji wskaźnika. Jeśli zapomniałeś o nawiasach, operator.-Połączy się silniej niż * -operator i sprawi, że nasz przykład zostanie wykonany jako:
*(aPointer.method()); // Not our intention!
Niektóre z innych odpowiedzi wspominają również, że operatory C ++ mogą być przeciążone i że nie jest to tak powszechne.
new SomeClass()
zwraca wskaźnik ( SomeClass *
), a nie SomeClass
obiekt. Zaczynasz od zadeklarowania, anObject
a potem aPointer
używasz p
.
W języku C ++ 0x operator otrzymuje drugie znaczenie, wskazujące typ zwracanej funkcji lub wyrażenia lambda
auto f() -> int; // "->" means "returns ..."
::
jest w rzeczywistości operatorem, takim jak .
or ->
, i jest w standardzie nazywany „operatorem rozpoznawania zakresu”.
->
jest używany podczas uzyskiwania dostępu do danych, do których masz wskaźnik.
Na przykład, możesz utworzyć wskaźnik ptr do zmiennej typu int intVar w następujący sposób:
int* prt = &intVar;
Możesz wtedy użyć funkcji, takiej jak foo, na niej tylko przez wyłuskiwanie tego wskaźnika - aby wywołać funkcję na zmiennej, na którą wskazuje wskaźnik, zamiast na wartości liczbowej lokalizacji pamięci tej zmiennej:
(*ptr).foo();
Bez nawiasów tutaj kompilator zrozumiałby to jako *(ptr.foo())
wynikający z pierwszeństwa operatorów, czego nie chcemy.
W rzeczywistości jest to to samo, co pisanie
ptr->foo();
Jako ->
dereferences ten wskaźnik, a więc wywołuje funkcję foo()
na zmiennej, na którą wskazuje wskaźnik dla nas.
Podobnie możemy użyć, ->
aby uzyskać dostęp lub ustawić członka klasy:
myClass* ptr = &myClassMember;
ptr->myClassVar = 2;
->
operatora dla niektórych typów iteratorów, więc trzeba było użyć*.
. Wiele bibliotek definiuje je niespójnie. Staje się naprawdę irytujące, gdy pracujesz z szablonami i nie znasz dokładnego typu.