2013-03-16 41 views
19

Tôi tự hỏi nếu có lý do tại sao chúng tôi không thể khởi tạo thành viên tại tuyên bố của họ.Tại sao chúng ta không thể khởi tạo thành viên lớp học khi khai báo?

class Foo 
{ 
    int Bar = 42; // this is invalid 
}; 

Tương đương với việc sử dụng danh sách khởi tạo hàm tạo.

class Foo 
{ 
    int Bar; 
public: 
    Foo() : Bar(42) {} 
} 

Sự hiểu biết cá nhân của tôi là ví dụ trên rõ ràng hơn và có chủ ý hơn. Hơn nữa đây là một cú pháp ngắn hơn. Và tôi không thấy bất kỳ khả năng nhầm lẫn nào với các yếu tố ngôn ngữ khác.

Có bất kỳ giải thích chính thức nào về vấn đề này không?

+20

Bạn có thể sử dụng C++ 11. – chris

+0

Trình biên dịch của tôi nói với tôi: * "Lỗi: bộ khởi tạo thành viên dữ liệu không được phép" *. – danijar

+2

Vì vậy, trình biên dịch của bạn không hỗ trợ (tất cả) C++ 11. –

Trả lời

18

Việc khởi tạo các thành viên không tĩnh không thể được thực hiện như thế này trước C++ 11. Nếu bạn biên dịch với trình biên dịch C++ 11, nó sẽ vui vẻ chấp nhận mã bạn đã đưa ra.

Tôi tưởng tượng rằng lý do không cho phép nó ngay từ đầu là do khai báo thành viên dữ liệu không phải là định nghĩa. Không có đối tượng nào được giới thiệu. Nếu bạn có một thành viên dữ liệu chẳng hạn như int x;, không có đối tượng int được tạo cho đến khi bạn thực sự tạo đối tượng thuộc loại của lớp. Vì vậy, một initializer trên thành viên này sẽ gây hiểu nhầm. Chỉ trong quá trình xây dựng, một giá trị có thể được gán cho thành viên, đó chính xác là danh sách khởi tạo thành viên.

Cũng có một số vấn đề kỹ thuật cần thực hiện trước khi khởi tạo thành viên không tĩnh. Hãy xem xét các ví dụ sau:

struct S { 
    int i(x); 
    // ... 
    static int x; 
}; 

struct T { 
    int i(x); 
    // ... 
    typedef int x; 
}; 

Khi những cấu trúc đang được phân tích, tại thời điểm phân tích các thành viên i, nó là mơ hồ cho dù đó là một tuyên bố thành viên dữ liệu (như trong S) hoặc khai báo hàm thành viên (như trong số T).

Với chức năng bổ sung, đây không phải là vấn đề vì bạn không thể khởi tạo thành viên bằng cú pháp parantheses này. Bạn phải sử dụng một cú đúp-hoặc-bằng-initializer như:

int i = x; 
int i{x}; 

Những chỉ có thể là dữ liệu thành viên và vì vậy chúng tôi không có vấn đề nữa.

Xem đề xuất N2628 để có cái nhìn kỹ lưỡng hơn về các vấn đề cần được xem xét khi đề xuất trình khởi tạo thành viên không tĩnh.

+0

Tại thời điểm 'i' đang được phân tích cú pháp' x' là không xác định, vì vậy không nên chỉ đơn giản là dẫn đến lỗi biên dịch? Các tờ khai chuyển tiếp truyền thống được sử dụng để giải quyết các vấn đề đó. – doc

4

Lý do chính là khởi tạo áp dụng cho một đối tượng hoặc một phiên bản và trong tuyên bố trong lớp không có đối tượng hoặc ví dụ ; bạn không có điều đó cho đến khi bạn bắt đầu xây dựng .

Đã có một số tiến hóa trong lĩnh vực này. Đã có, tại rất kết thúc tiêu chuẩn hóa C++ 98, ủy ban bổ sung khả năng để làm điều này cho các thành viên const tĩnh của loại --- chủ yếu vì chúng có thể được sử dụng trong ngữ cảnh nơi trình biên dịch phải có khả năng để xem khởi tạo. Trong C++ 11, ngôn ngữ đã được mở rộng để cho phép chỉ định trình khởi tạo trong tuyên bố, nhưng đây chỉ là viết tắt — việc khởi tạo thực tế vẫn diễn ra ở trên cùng của hàm tạo.

+2

Việc khởi tạo các thành viên dữ liệu cũng sẽ vẫn xảy ra theo thứ tự khai báo. –

+0

@CaptainObvlious Đúng, nhưng tôi đoán những gì James có nghĩa là chỉ có initialisation luôn luôn xảy ra trong quá trình thực hiện danh sách init ctor, theo thứ tự mà các thành viên đã được tuyên bố như bạn nói - thay vì ví dụ bị ảnh hưởng bởi vị trí khai báo thành viên liên quan đến từ chối/định nghĩa của ctor. –

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