Czego mogę użyć zamiast operatora strzałki, `->`?

112

Dlaczego operator strzałki ( ->) jest synonimem?

ROCZNIE
źródło

Odpowiedzi:

148

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).

Greg Hewgill
źródło
9
Problemy z przeciążeniem są dużo mniej niezwykłe, niż myślisz. Niedawno implementatorzy STL nie mieli przeciążonego ->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.
Konrad Rudolph
1
możesz też zrobić a[0].bzamiast (*a).b. Ale nie byłby tak odpowiednio skonstruowany.
Sellorio
2
Chłopcze, po wielu latach programowania w C #, powrót do C ++ jest nie tylko obciążeniem poznawczym, składnia c ++ jest po prostu brzydka i obrzydliwa. Po użyciu mam ochotę wziąć prysznic. Programy napisane w c i c ++ po prostu zachęcają do złego programowania. Apple starał się uczynić język tak pięknym jak Pascal.
ATL_DEV,
@ATL_DEV Twierdzę, że wiele brzydkich rzeczy nie jest już uważanych za idiomatyczne, ale niestety nie oznacza to, że możesz sobie pozwolić na to, aby nie znać ich jako praktykującego programistę C ++. Ścieżka ładna składniowo często nie jest ścieżką ładną semantycznie, ale ona też jest coraz lepsza, a nie gorsza. Ale znowu mam C ++ Stockholm Syndrome.
Tim Seguine
@TimSeguine Jeśli kiedykolwiek chcesz zobaczyć ładny kod, spójrz do dokumentacji wewnątrz Macintosha. Myślę, że wymyślili CamelCase. Bardzo opisowe nazwy zmiennych i elegancko sformatowany kod. Udało im się uczynić ich późniejszy kod C prawie tak wspaniały, jak ich wcześniejszy kod Pascal.
ATL_DEV
70

a->bjest generalnie synonimem (*a).b. Nawiasy są tutaj konieczne ze względu na siłę wiązania operatorów, *a .: *a.bnie 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ć.

Konrad Rudolph
źródło
1
Przez binding strengthto znaczy pierwszeństwo operatora? jeśli nie, jaka jest różnica między nimi?
vishnuprasanth
1
@Vizkrig Tak, te dwa terminy są używane zamiennie (chociaż „pierwszeństwo operatorów” wydaje się być znacznie częstsze, przynajmniej w ostatnich latach).
Konrad Rudolph
45

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 anObjecti 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.

ROCZNIE
źródło
8
new SomeClass()zwraca wskaźnik ( SomeClass *), a nie SomeClassobiekt. Zaczynasz od zadeklarowania, anObjecta potem aPointerużywasz p.
musiphil
Ogólnie to wyjaśnienie jest teoretycznie bardzo trafne, tylko zmiana obiektów powoduje, że jest ono trochę zagmatwane. Ale proces jest lepiej opisany
Code Man
17

W języku C ++ 0x operator otrzymuje drugie znaczenie, wskazujące typ zwracanej funkcji lub wyrażenia lambda

auto f() -> int; // "->" means "returns ..."
Johannes Schaub - litb
źródło
1
Technicznie rzecz biorąc, nie jest już tam „operatorem”, czy nie?
Martin Ba
6
@Martin większość ludzi używa słowa „operator” do wielu rzeczy, które nie są bezpośrednio używane do obliczania wartości. Podobnie jak w przypadku „::” („operator zasięgu”). Nie wiem, jaki jest punkt widzenia normy w tej sprawie. W sensie abstrakcyjnym można by postrzegać „->” jako operator funkcyjny odwzorowujący sekwencję typów (parametrów) na typ zwracany, podobnie jak operator haskell, który również jest zapisywany jako „->”.
Johannes Schaub - litb
6
Poddaję się! :-P
Martin Ba
2
@ JohannesSchaub-litb: ::jest w rzeczywistości operatorem, takim jak .or ->, i jest w standardzie nazywany „operatorem rozpoznawania zakresu”.
musiphil
13

Najczęściej czytam od prawej do lewej i wołam „in”

foo->bar->baz = qux->croak

staje się:

"Baz in bar in foo staje się rechocząc w qux."

Teta
źródło
1

-> 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; 
Tryb Ghost
źródło
0

Możesz użyć ->, aby zdefiniować funkcję.

auto fun() -> int
{
return 100;
}

To nie jest lambda. To naprawdę funkcja. „->” wskazuje zwracany typ funkcji.

Zhang
źródło