2016-01-21 13 views
7

Tôi đang cố gắng để hiểu được sự nhất quán trong các lỗi được ném vào chương trình này:Pointer-to-thành viên nhầm lẫn

#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(); 

} 

Đầu ra là 10 10. Tôi dán nhãn 4 điểm của chương trình, nhưng (3) là mối quan tâm lớn nhất của tôi:

  1. x được lấy thường từ bên trong một hàm thành viên.
  2. x đối tượng được tìm nạp bằng toán tử phạm vi và giá trị lvalue cho đối tượng x được trả về.
  3. Được tặng trả lại số int giá trị bằng (2), tại sao sau đó &A::x trả về không int* nhưng thay vì trả về int A::*? Toán tử phạm vi thậm chí được ưu tiên trước toán tử & để A::x phải chạy trước, trả về giá trị int trước khi địa chỉ được thực hiện. tức là điều này phải giống như &(A::x)? (Thêm dấu ngoặc đơn thực sự hoạt động bằng cách này).
  4. Một chút khác biệt ở đây tất nhiên, toán tử phạm vi đề cập đến một thành viên lớp nhưng không có đối tượng nào được tham chiếu.

Vậy tại sao chính xác không A::x không trả về địa chỉ của đối tượng x nhưng thay vì trả về địa chỉ của các thành viên, bỏ qua ưu tiên của :: trước &?

Trả lời

3

Tiêu chuẩn C++ không chỉ định rõ ràng quyền ưu tiên của toán tử; có thể suy ra ưu tiên toán tử một cách ngầm định từ các quy tắc ngữ pháp, nhưng cách tiếp cận này không đánh giá cao trường hợp đặc biệt không thường xuyên như thế này mà không phù hợp với mô hình ưu tiên của toán tử truyền thống.

[expr.unary.op]/3:

Kết quả của & hành unary là một con trỏ đến toán hạng của nó. Toán hạng phải là một lvalue hoặc đủ điều kiện-id. Nếu toán hạng là một có trình độ-id đặt tên một tổ chức phi tĩnh hoặc biến thể thành viên m của một số lớp C với loại T, kết quả có kiểu 'con trỏ tới thành viên của lớp C loại T' và là một prvalue chỉ định C::m . Nếu không, nếu loại biểu thức là T, kết quả có loại 'con trỏ đến T' và là giá trị là địa chỉ của đối tượng được chỉ định hoặc con trỏ đến hàm được chỉ định.

/4:

Một con trỏ tới thành viên chỉ được hình thành khi một rõ ràng & được sử dụng và toán hạng của nó là một có trình độ-id không kèm theo trong ngoặc đơn. [Lưu ý: có nghĩa là, biểu thức &(qualified-id), trong đó id đủ điều kiện được đặt trong dấu ngoặc đơn, không tạo biểu thức loại 'con trỏ thành thành viên'.

[expr.prim.general]/9:

Một lồng nhau-tên-specifier mà biểu thị một lớp học, tùy chọn tiếp theo là từ khóa template, và sau đó theo sau là tên của một thành viên của lớp học đó hoặc một trong các lớp cơ sở của nó, là đủ điều kiện-id.

gì nó còn tăng cường là một biểu hiện của hình thức &A::x có kiểu "con trỏ tới thành viên x của lớp A" nếu x là thành viên không tĩnh của một lớp phi đoàn A, và điều hành ưu tiên không ảnh hưởng đến điều này.

8

Về cơ bản, nó chỉ là cú pháp &A::x (không có biến thể) đã được chọn để có nghĩa là con trỏ thành viên.

Nếu bạn viết, ví dụ: &(A::x), bạn sẽ nhận được con trỏ đơn giản mà bạn mong đợi.

Thông tin thêm về con trỏ-thành viên, bao gồm ghi chú về thuộc tính này, có thể được tìm thấy here.

+0

Tôi nghĩ nếu nó hoạt động theo cách khác, điều đó sẽ dẫn đến nhiều nhầm lẫn hơn. Cùng một chuỗi số nhận dạng và toán tử, tham chiếu cùng loại và thành viên chính xác, có nghĩa là hai thứ khác nhau tùy thuộc vào phạm vi: âm thanh như sự cố với tôi. –

+0

@JohnSensebe chắc chắn. Ban đầu tôi viết "quirk", nhưng đây thực ra là một lựa chọn rất hợp lý, mặc dù ban đầu nó có vẻ lạ lùng. – Quentin