2013-03-21 19 views
5

Tôi biết rằng tôi có thể có được một con trỏ tới thành viên dữ liệu cho một lớp học hoặc struct nhưng dòng cuối cùng của đoạn mã sau thất bại trong việc biên dịch:Chuyển đổi thành viên dữ liệu để làm mất hiệu lực *

struct abc 
{ 
    int a; 
    int b; 
    char c; 
}; 

int main() 
{ 
    typedef struct abc abc; 
    char abc::*ptt1 = &abc::c; 
    void *another_ptr = (void*)ptt1; 
} 

tại sao có thể không Tôi chuyển đổi ptt1 để another_ptr? Chúng ta đang nói về con trỏ vì vậy một con trỏ nên có một chiều hướng tương tự như nhau (mặc dù khái niệm khác nhau)

+0

Thông báo lỗi là gì? –

+1

"typedef struct abc abc;" Có thật không? –

+0

Tôi đang sử dụng MSVC2012: lỗi C2440: 'loại diễn viên': không thể chuyển đổi từ 'char abc :: *' thành 'void *' – Paul

Trả lời

9

Một con trỏ để không tĩnh thành viên lớp loại là không giống như một đối tượng con trỏ kiểu; chúng cư xử rất khác nhau. Trong thực tế, bạn thậm chí không thể dereference một con trỏ đến thành viên với *. Để truy cập một thành viên thông qua một con trỏ tới thành viên, thay vào đó bạn sử dụng các toán tử .*->*. Nếu bạn có thể truyền nó vào một loại con trỏ đối tượng như thế này, điều gì sẽ xảy ra, sau đó, nếu bạn bỏ qua nó với *?

Chỉ phản đối loại con trỏ có một chuyển đổi tiêu chuẩn để void* (§4.10):

Một prvalue kiểu "con trỏ đến cvT", nơi T là một loại đối tượng, có thể được chuyển đổi sang một giá trị của loại "con trỏ đến cvvoid".

Họ đang rất khác nhau mà tiêu chuẩn thậm chí đi ra khỏi con đường của mình để đảm bảo rằng thuật ngữ "con trỏ" không bao gồm các con trỏ tới các thành viên không tĩnh (§3.9.2):

Ngoại trừ các con trỏ tới các thành viên tĩnh, văn bản đề cập đến "con trỏ" không áp dụng cho con trỏ đến các thành viên.

+0

Về điều duy nhất bạn có thể thực hiện với 'void *' là đưa nó trở lại bản gốc loại anyway, do đó, câu hỏi về việc sử dụng có thể không nhất thiết phải hợp lệ. Bạn không thể dereference một 'void *' với '*' hoặc. –

+0

@JamesKanze Rephrased nó để làm cho điểm rõ ràng hơn. –

+0

Ngoại trừ việc nó vẫn không rõ ràng ý bạn là gì bởi "con trỏ bình thường". Chỉ các con trỏ tới các đối tượng (theo nghĩa C++) có thể được chuyển thành 'void *'. Con trỏ đến các thành viên và con trỏ đến hàm không thể. –

0

Bạn đang cố gắng làm điều gì đó như thế này?

struct ABC 
{ 
    int a; 
    int b; 
    char c; 
}; 

int main() 
{ 
    ABC abc; 
    char *ptt1 = &abc.c; 
    void *another_ptr = (void*)ptt1; 
} 
+0

Có nhưng không có đối tượng – Paul

+0

Nếu không có đối tượng thì điều đó là vô nghĩa. – Damon

+1

Đây là một sự tương tự khủng khiếp kéo dài: Những gì bạn đã cố gắng giống như cố gắng để đóng đinh vào bản thiết kế của một ngôi nhà thay vì chính ngôi nhà. –

2

Lý do chính là vì không có yêu cầu rằng một con trỏ tới thành viên có quy mô và trình bày tương tự như một con trỏ đến dữ liệu. Trong thực tế, thật khó để tưởng tượng một con trỏ cho một thành viên dữ liệu không thể phù hợp với void*, vì một con trỏ tới thành viên dữ liệu thực sự chỉ cần chứa khoản bù . Nói chung, con trỏ tới thành viên dữ liệu sẽ là không bao giờ cần lớn hơn size_tvoid* phải là ít nhất là lớn nhất là size_t. Mặt khác, nó có thể dễ dàng chứa các mẫu bit không hợp pháp trong một con trỏ. Thực tế, như Steve Jessop chỉ ra, con trỏ tới thành viên yêu cầu thông tin bổ sung, vì thành viên nằm trong một cơ sở ảo, bù đắp của nó phụ thuộc vào lớp dẫn xuất nhất và phải được tính toán động, dựa trên thông tin bổ sung trong con trỏ.

Thông thường, void* chỉ có thể chứa con trỏ đến dữ liệu. Nó phải lớn bằng con trỏ dữ liệu lớn nhất (thường là a char*), nhưng con trỏ đến hàm và con trỏ thành viên có thể lớn hơn và không vừa (và trỏ đến hàm thành viên gần như không bao giờ khớp).

+0

"một con trỏ đến một thành viên dữ liệu thực sự chỉ cần chứa một offset" - trừ khi thành viên nằm trong một lớp cơ sở ảo, trong trường hợp đó là cần thiết hơn (tôi nghĩ. - chức năng đó là khó khăn?). –

+0

@SteveJessop Bạn nói đúng. Tôi không biết nơi tôi đã nhìn thấy nó được trình bày như một sự bù đắp đơn giản. Với VC 2012, chế độ 32 bit, 'int *' có kích thước 4, 'int Class :: *' 12. (Nghĩ lại thì, tôi nghĩ lần cuối cùng tôi thực sự xem xét nó một cách chi tiết là trước đây nhiều thừa kế đã được thêm vào ngôn ngữ. Và sau đó, khó khăn duy nhất là các hàm ảo.) –

Các vấn đề liên quan