2011-03-27 24 views
11

tôi thấy một số mã như sau:Cách sử dụng của công đoàn trong một lớp

class A 
{ 
private: 
    union { 
     B *rep; 
     A *next; 
    }; // no variables of this anonymous defined! 

    void func() 
    { 
     A *p = new A; 

     p->next = NULL; // why p has a member variable of 'next'? 
    } 
}; 

tôi đã biên soạn mã trên với VS2010 mà không cần bất kỳ lỗi. Đây là câu hỏi,

tại sao p có biến thành viên 'tiếp theo'?

union { 
     B *rep; 
     A *next; 
    }; 

Theo như tôi biết, đây là một liên minh ẩn danh mà thậm chí không xác định biến. Làm thế nào chúng ta có thể truy cập vào các biến thành viên bên trong liên minh này như thế?

Trả lời

16

Bởi vì đó là khá nhiều những gì một đoàn vô danh không, nó định nghĩa zero-hoặc-nhiều biến trong không gian tên kèm theo (mà trong một khai báo lớp khiến họ tên trường) mà chiếm bộ nhớ chồng chéo. Do đó, việc sử dụng nó giống như khi bạn khai báo

class A 
{ 
private: 
    B *rep; 
    A *next; 

    void func() 
    { 
     A *p = new A; 

     p->next = NULL; 
    } 
}; 

... trừ đại diện và không gian chồng chéo chiếm tiếp theo (hoặc cho hai con trỏ có cùng kích thước, cùng một không gian) và do đó tất cả những nguy hiểm và lợi ích đi kèm với một liên minh được đặt tên.

+0

'Bởi vì đó là điều mà một công đoàn ẩn danh thực hiện' - một điểm tốt là gì. Nếu tôi cung cấp một biến ở cuối định nghĩa công đoàn, thì mã sẽ không chính xác nữa - cảm ơn bạn – q0987

0

Tôi không thực sự chắc chắn tôi hiểu câu hỏi của bạn.

A có thành viên p, bởi vì bạn đã khai báo nó trong A bên trong một liên minh ẩn danh cùng với đại diện.

Bạn đã khai báo biến! Nó chỉ là 'đại diện' và 'tiếp theo' chia sẻ cùng một bộ nhớ.

Bạn có thể truy cập nó theo cách bạn đã làm.

công đoàn ẩn danh (giống như cấu trúc) đặt thành viên của họ trong cùng một không gian tên như không gian tên ở trên.

Đó là hữu ích cho ví dụ:

union W00t { 
    struct { 
     uint32_t a,b; 
    }; 
    struct { 
     uint64_t c; 
    }; 
} 
+0

câu trả lời của bạn không liên quan đến câu hỏi của tôi. Tôi hỏi "tại sao biến p có thể truy cập biến tiếp theo?" – q0987

+0

mh Tôi không nhận được nó xin lỗi ^^. Bạn DID khai báo một biến. Nó chỉ là nó không có tên, do đó sử dụng không gian tên trên? Tôi không biết phải nói gì. –

+0

tiếp theo thực sự là một phần của A. Như là đại diện. Cả hai đều là thành viên ... Nhưng đại diện và tiếp theo chia sẻ cùng một bộ nhớ 64 bit. ((Và p là A *, do đó một con trỏ đến một thể hiện A, do đó có tất cả các thành viên của A.)) –

0

Tôi ngạc nhiên rằng có một trình biên dịch hiện đại vẫn cho phép cấu trúc đó. Nó là một trong những ngày đầu của C, khoảng năm 1975. Trong những ngày đó, cấu trúc và các thành viên công đoàn không thực sự gắn với một cấu trúc cụ thể, nhưng chứa đựng như là một thuộc tính bù đắp từ một địa chỉ cơ sở và một kiểu dữ liệu.

Kết quả cuối cùng là sử dụng cấu trúc hoặc liên kết phù hợp với đúng mã với các biểu thức được đánh giá như mong đợi. Sự khác biệt duy nhất là việc sử dụng sai một thành viên cấu trúc với một con trỏ không được liên kết với loại sẽ không bị gắn cờ là lỗi. Tôi không nghĩ rằng có bất kỳ lý do cụ thể nào để không thực thi liên kết — K & R gợi ý rằng các trình biên dịch trong tương lai hy vọng sẽ kiểm tra việc sử dụng này — có lẽ chỉ để lưu không gian bảng biểu tượng trong vùng đất 16 bit.

+0

gcc mới nhất thích nó. Và nó có nghĩa là bạn sử dụng union {struct {}} ... không cần phải có một phạm vi/tên khác ở giữa –

+1

Tất nhiên các trình biên dịch cho phép cấu trúc đó là một phần của tiêu chuẩn (và vẫn là, trong C++ 0x). Tôi sẽ đăng phần liên quan. –

+0

Nó cũng vẫn có sử dụng thực tế ngoài việc lạm dụng để tiết kiệm không gian. Rất nhiều thứ "xấu" có thể làm trong C và C++ là cần thiết trong một số trường hợp khi xử lý các bố trí vật lý được áp đặt, vì vậy trong khi ở trên sẽ là xấu nếu tiết kiệm không gian là mục đích duy nhất (mặc dù thậm chí sẽ được tha thứ trên một nhỏ thiết bị chỉ với một vài KB để chơi), nó có thể hoàn toàn quan trọng trong một số trường hợp. –

11

Dưới đây là trích dẫn từ các tiêu chuẩn kiểm soát hành vi này: phần [class.union] (từ ngữ từ C++ 0x dự thảo n3242)

Một đoàn của mẫu union {viên-đặc điểm kỹ thuật} ; được gọi là vô danh liên hiệp; nó xác định một đối tượng chưa được đặt tên của kiểu chưa đặt tên. Đặc điểm thành viên của một liên minh ẩn danh chỉ được phép sử dụng các thành viên dữ liệu không tĩnh. [Lưu ý: Không thể khai báo các loại và chức năng lồng nhau trong một liên minh ẩn danh.- lưu ý kết thúc] Tên của các thành viên của một liên minh ẩn danh sẽ khác với tên của bất kỳ thực thể nào khác trong phạm vi mà công đoàn ẩn danh được khai báo. Đối với mục đích tra cứu tên, sau khi xác định công đoàn ẩn danh, các thành viên của liên minh ẩn danh được coi là đã được xác định trong phạm vi mà công đoàn ẩn danh được tuyên bố.

+0

bạn luôn có thể cung cấp câu trả lời! - cảm ơn bạn – q0987

+2

@ q0987: Tôi nghĩ [Jon] (http://stackoverflow.com/questions/5453170/usage-of-union-inside-a-class/5453262#5453262) giành được dấu kiểm. Tôi không làm gì ngoài trích dẫn tiêu chuẩn vì mục đích tham khảo, để chứng minh rằng câu trả lời dễ đọc hơn của anh ấy là chính xác. Tôi đã có thể sử dụng một bình luận, nhưng tôi đã học được từ lâu rằng trích dẫn từ tiêu chuẩn thường không FIT trong một bình luận, cũng không làm họ định dạng tốt. –

+0

có, tôi đã thực hiện các thay đổi theo yêu cầu của bạn. -- cám ơn – q0987

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