2016-01-21 15 views
7

Próbuję zrozumieć spójność błędu, który jest wyrzucany w tym programie:wskaźnik do członka zamieszanie

#include <iostream> 

class A{ 
public: 
    void test(); 
    int x = 10; 

}; 

void A::test(){ 

    std::cout << x << std::endl; //(1) 
    std::cout << A::x << std::endl; //(2) 

    int* p = &x; 
    //int* q = &A::x; //error: cannot convert 'int A::*' to 'int*' in initialization| //(3) 


} 

int main(){ 

    const int A::* a = &A::x; //(4) 

    A b; 

    b.test(); 

} 

Wyjście jest 10 10. Napisałem 4 punkty programu, ale (3) to mój największy problem:

  1. jest pobierany normalnie z poziomu funkcji członka.
  2. x obiektu jest pobierany za pomocą operatora zakres i lwartością do obiektu x zwrotu.
  3. Po otrzymaniu A::x zwrócono wartość lw (2), dlaczego zatem &A::x nie zwróci int*, ale zamiast tego zwróci int A::*? Operator zakresu ma pierwszeństwo przed operatorem &, więc powinien zostać uruchomiony jako pierwszy, zwracając wartość l, przed podaniem adresu. to znaczy powinienem być taki sam jak &(A::x)? (Dodawanie nawiasów faktycznie działa po drodze).
  4. Oczywiście nieco inaczej, operator zasięgu odnosi się do członka klasy, ale bez obiektu, do którego się odnosi.

Więc dlaczego dokładnie nie A::x nie zwróci adres obiektu x lecz zwraca adres elementu, pomijając pierwszeństwo :: przed &?

Odpowiedz

3

standardem C++ nie jawnie określić pierwszeństwo operatora; można domyślnie wyprowadzić pierwszeństwo operatorów z reguł gramatycznych, ale podejście to nie docenia sporadycznego przypadku specjalnego, takiego jak ten, który nie pasuje do tradycyjnego modelu pierwszeństwa operatora.

[expr.unary.op]/3:

Wynik jednoargumentowy & operatora jest wskaźnikiem jej argumentu. Argument będzie wartością l lub kwalifikowanym identyfikatorem. Jeśli operand jest kwalifikowaną id nazywania non-statyczne lub wariant członu m jakiejś klasie C z rodzaju T wynik musi wpisać „wskaźnik do członka klasy C typu T” i jest prvalue wyznaczaniu C::m . W przeciwnym razie, jeśli typ wyrażenia to T, wynik ma typ "wskaźnik do T" i jest prwartością, która jest adresem wyznaczonego obiektu lub wskaźnikiem do wyznaczonej funkcji.

/4:

Wskaźnik z członem powstaje tylko wtedy, gdy stosuje się wyraźnie & i jego operandu jest wykwalifikowany ID nie zamkniętym w nawiasach. [] Uwaga: , tj. Wyrażenie &(qualified-id), gdzie kwalifikowany identyfikator jest zawarty w nawiasach, nie tworzy wyrażenia typu "wskaźnik do elementu".

[expr.prim.general]/9:

zagnieżdżone nazwa-specyfikator oznaczająca klasę, ewentualnie następnie przez parametr template, a następnie przez nazwę członkiem tej klasy lub jednej z jej klas bazowych jest kwalifikowany identyfikator .

Co to wszystko sprowadza się do tego, że wyrazem postaci &A::x ma typu „wskaźnik do członka x klasy A” jeśli x jest non-static członkiem non-union klasy A i operator pierwszeństwo nie ma na to wpływu.

8

Zasadniczo, jest to po prostu, że składnia &A::x (bez zmian) został wybrany na myśli wskaźnik do członka.

Jeśli piszesz, na przykład, &(A::x), dostaniesz zwykły wskaźnik można oczekiwać.

Więcej informacji na temat wskaźników do członków, w tym uwagi na temat tej właściwości, można znaleźć here.

+0

Myślę, że gdyby działało inaczej, doprowadziłoby to do większej dezorientacji. Ta sama sekwencja identyfikatorów i operatorów, odwołująca się do dokładnie tych samych typów i członków, co oznacza dwie różne rzeczy w zależności od zakresu: brzmi dla mnie jak kłopot. –

+0

@ Johno zdecydowanie. Oryginalnie napisałem "dziwactwo", ale w rzeczywistości jest to bardzo rozsądny wybór, chociaż może wydawać się dziwne na początku. – Quentin