2012-10-24 38 views
6

Tôi ngạc nhiên này không làm việc:Tôi có thể khởi tạo một công đoàn trong bộ khởi tạo mem không?

union DlDatum 
{ 
    float mFloat; 
    s32 mInteger; 
}; 

class DlDbE 
{ 
public: 
    DlDbE(float f) : mData.mFloat(f) {}; 
private: 
    DlDatum mData; 
}; 

Có cách nào để khởi tạo một liên minh trong một C++ constructor danh sách mem-initializer?

Cập nhật: Trả lời là tạo các hàm tạo cho công đoàn. Không biết rằng có thể được thực hiện. Dưới đây là những gì tôi đã làm:

union DlDatum 
{ 
    float mFloat; 
    s32 mInteger; 
    bool mBoolean; 
    u32 mSymbol; 
    u32 mObjIdx; 

    DlDatum(  ) : mInteger(0) {} 
    DlDatum(float f) : mFloat(f) {} 
    DlDatum(s32 i) : mInteger(i) {} 
    DlDatum(bool b) : mBoolean(b) {} 
    DlDatum(u32 s) : mSymbol(s) {} // this ctor should work for objIdx also 
}; 

class DlDbE 
{ 
public: 
    DlDbE() {} 
    DlDbE(float f) : mData(f) {} 
    DlDbE(u32 i ) : mData(i) {} 
    DlDbE(bool b ) : mData(b) {} 
    ...etc.. 
private: 
    DlDatum mData; 
}; 
+0

http://stackoverflow.com/questions/321351/initializing-a-union-with-a-non-trivial-constructor – Mysticial

Trả lời

11

Giống như bất kỳ thành viên nào khác, nếu bạn muốn xây dựng liên minh, bạn sẽ phải cung cấp cho công đoàn một nhà xây dựng và gọi đó.

+0

Không biết công đoàn có thể có nhà thầu. Tôi sẽ thử xem. Họ có thể có các thành viên không? –

+0

@RafaelBaptista Có, không chỉ các chức năng ảo. Họ cũng không thể kế thừa từ bất cứ thứ gì hoặc được thừa hưởng từ. –

+0

Thú vị. Giống như các lớp gimped. –

9

Trong C++ 03 và trước khi bạn bị giới hạn viết một hàm tạo cho công đoàn của bạn.

Trong C++ 11 khởi tạo đồng bộ mở rộng cú pháp của khởi tạo tổng hợp thành danh sách khởi tạo bộ dựng. Điều này có nghĩa rằng cú pháp khởi tạo tổng hợp cũ tốt như

DlDatum d = { 3.0 }; 

mà tất cả chúng ta đều biết và yêu thích từ C và khởi tạo các thành viên đầu tiên của đoàn, bây giờ có thể được sử dụng trong danh sách constructor khởi tạo cũng

union DlDatum 
{ 
    float mFloat; 
    s32 mInteger; 
}; 

class DlDbE 
{ 
public: 
    DlDbE(float f) : mData{f} {} 
private: 
    DlDatum mData; 
}; 

Tính năng này chỉ cho phép bạn "nhắm mục tiêu" thành viên không tĩnh đầu tiên của công đoàn để khởi tạo. Nếu bạn cần một cái gì đó linh hoạt hơn, sau đó nó là trở lại để viết các nhà thầu.

1

@AndreyT đưa ra một câu trả lời tuyệt vời mà tôi sẽ mở rộng với một lời khuyên thực tế nhỏ.

Tôi có xu hướng sử dụng công đoàn để dễ dàng truy cập vào giá trị bitmap mà không có bitwise tẻ nhạt và xấu xí và/bitwise hoặc của. Tôi nghĩ đây là một thực tế khá phổ biến.

Một kỹ thuật tôi đã sử dụng trong một thời gian để làm cho quá trình dễ dàng hơn là nếu tôi đang làm việc với một bitmap dưới 32bits Tôi tuyên bố nó như là một vô danh struct bên trong một đoàn cùng với người bạn đồng hành DWORD thành viên dữ liệu. Ví dụ:

union UNICODECONTROL{ 
    DWORD   dwAccessor; 
    struct{ 
     unsigned unicode_01 : 1; 
     unsigned unicode_02 : 1; 
     unsigned unicode_03 : 1; 
     unsigned unicode_04 : 1; 
     unsigned unicode_05 : 1; 
     unsigned unicode_06 : 1; 
     unsigned unicode_07 : 1; 
     unsigned unicode_08 : 1; 
     unsigned unicode_09 : 1; 
     unsigned unicode_10 : 1; 
    }; 
}; 

Với điều đó tại chỗ nó sẽ hoạt động giống như chức năng 'người truy cập'. Nếu bạn muốn thiết lập các giá trị bạn có thể làm như vậy trong một lần bằng cách gán một số với bitmap thích hợp cho 'accessor' này. Bạn muốn không phải tất cả chúng - cũng là một miếng bánh. Nó đặc biệt làm việc rất tốt với các cửa sổ đăng ký. Để lưu trữ giá trị của bitmap công đoàn, tất cả những gì bạn cần làm chỉ là viết DWORD vào sổ đăng ký! Truy xuất nó sau này để tái khởi tạo cũng không kém phần đơn giản.

A DWORD là một trong các kiểu gốc của sổ đăng ký và bạn không cần phải gây rối xung quanh chức năng chuyển đổi tĩnh hoặc viết thủ công. Nếu bạn có bitmap dài hơn 32 bit, bạn có thể khai báo một số nguyên có kích thước 64Bit và nó sẽ hoạt động theo cách tương tự thường - và cũng như với sổ đăng ký là QUADWORD cũng là một kiểu gốc.

Trường hợp này mang trực tiếp vào những gì @AndreyT đề cập - nếu bạn muốn khởi tạo thuận tiện của một thành viên dữ liệu lớp ở định dạng bitmap/DWORD của tôi, tất cả những gì bạn phải làm là - như trong ví dụ - hãy đảm bảo 'accessor' là giá trị đầu tiên được khai báo trong liên minh. Sau đó, bạn có thể ghi danh sách trực tiếp với lược đồ C++ 11 '{}' mới. Không cần cho các nhà xây dựng công đoàn kỳ lạ chút nào!

Báo trước. Trường hợp các bit bitmap riêng biệt sống 'bên trong' thì trình truy cập DWORD sẽ phụ thuộc vào thiết lập căn chỉnh cho các cấu trúc của bạn. Điều này được đặt ở cấp trình biên dịch hoặc với câu lệnh __declspec(align(#)) trong MSVC++ và cú pháp tương tự trong các trình biên dịch khác.

Cuối cùng, cập nhật đã tìm hiểu trong khi thử các ý tưởng này trong một số trường hợp khác nhau gần đây. Mặc dù thực tế C++ 11 nói rõ ràng là hợp pháp để khởi tạo một công đoàn bằng biến đầu tiên của nó như được mô tả ở trên, MSVC++ dường như bỏ qua tiêu chuẩn này - hoặc 'không thực hiện'. Vì vậy nếu bạn đang sử dụng trình biên dịch Microsoft, bạn sẽ phải thực hiện một hàm tạo lộn xộn cho công đoàn của bạn nếu bạn muốn khởi tạo nó. Một sự xấu hổ, nhưng có lẽ việc tuân thủ tiêu chuẩn C++ 11 sẽ cải thiện trong các gói dịch vụ tiếp theo cho VS2013 và với lần lặp tiếp theo năm 2014 của toàn bộ IDE.

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