2012-05-23 38 views
22

Hãy xem xét những điều sau tình huống (giản thể):Các biến thành viên có thể được sử dụng để khởi tạo các thành viên khác trong danh sách khởi tạo không?

class Foo 
{ 
private: 
    int evenA; 
    int evenB; 
    int evenSum; 
public: 
    Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB) 
    { 
    } 
}; 

Khi tôi instanciate Foo như thế này:

Foo foo(1,3); 

sau đó evenA là 0, evenB là 2, nhưng evenSum sẽ được khởi tạo tới 2?

Tôi đã thử tính năng này trên nền tảng hiện tại của mình (iOS) và có vẻ như hoạt động, nhưng tôi không chắc liệu mã này có thể di chuyển hay không.

Cảm ơn sự giúp đỡ của bạn!

+0

Đây là một trong những góc nguy hiểm trong C++. – iammilind

+0

Codepad là nơi tuyệt vời để kiểm tra những thứ như vậy: http://codepad.org/uFgZpkwN –

+0

@Agent_L: Điều đó sẽ không cho bạn biết mã có thể di chuyển hay không. –

Trả lời

27

được xác định rõ ràng và di động, nhưng có khả năng xảy ra lỗi.

Thành viên được khởi tạo theo thứ tự chúng được khai báo trong nội dung lớp học, không phải thứ tự chúng được liệt kê trong danh sách khởi tạo. Vì vậy, nếu bạn thay đổi thân lớp, mã này có thể âm thầm thất bại (mặc dù nhiều trình biên dịch sẽ phát hiện ra điều này và phát ra một cảnh báo).


1. Từ [class.base.init] trong C++ chuẩn (s):

Trong một constructor không ủy thác, tiền thu được khởi tạo theo trình tự sau:

  • Đầu tiên, và chỉ dành cho hàm tạo của lớp dẫn xuất nhất (1.8), các lớp cơ sở ảo được khởi tạo theo thứ tự thứ tự chúng xuất hiện trên một chiều ngang trái-phải-phải của biểu đồ tuần hoàn hướng của các lớp cơ sở, trái sang phải”là thứ tự xuất hiện của các lớp cơ sở trong lớp có nguồn gốc cơ sở-specifier-list.
  • Sau đó, các lớp cơ sở trực tiếp được khởi tạo theo thứ tự khai báo khi chúng xuất hiện trong danh sách-specifier-list (bất kể thứ tự của bộ khởi tạo mem).
  • Sau đó, các thành viên dữ liệu không tĩnh được khởi tạo theo thứ tự chúng được khai báo trong định nghĩa lớp (một lần nữa bất kể thứ tự của bộ khởi tạo mem).
  • Cuối cùng, câu lệnh phức hợp của phần thân hàm tạo được thực hiện.

(Highlighting là của tôi.)

Phần này của tiêu chuẩn sau đó tiếp tục đưa ra một ví dụ về sử dụng các biến thành viên để khởi tạo các biến thành viên khác.

+0

ok vì vậy nếu Foo có một lớp cơ sở Bar ​​(không thừa kế công cộng ảo) và tôi đặt Bars constructor trong danh sách khởi tạo, nó sẽ luôn luôn được thực thi trước tất cả các initializers thành viên, ngay cả khi tôi đặt nó ở cuối danh sách khởi tạo? – Pontomedon

+0

@Pontomedon: Có. Các hàm tạo lớp cơ sở luôn luôn được gọi đầu tiên (ngay cả khi chúng không có trong danh sách). –

6

Thành viên được khởi tạo theo thứ tự chúng được khai báo trong định nghĩa lớp. Miễn là danh sách trình khởi tạo của bạn theo thứ tự này, nó sẽ ổn.

0

Điều này cũng được biên soạn mà không có lỗi trên g ++ 4.0.3 (6 tuổi hiện nay).

Tôi cảm thấy tự tin rằng điều này sẽ biên dịch tốt trên bất kỳ trình biên dịch hợp lý nào gần đây.

8

Có, cung cấp chúng đã được xây dựng. Chỉ cần đừng quên rằng thứ tự xây dựng là thứ tự của các khai báo trong định nghĩa lớp học , không phải thứ tự của bộ khởi tạo trong công cụ xây dựng . Và trình biên dịch thường sẽ không cho bạn biết nếu bạn sử dụng một biến trước khi nó được xây dựng. Trong trường hợp của bạn, ví dụ, nếu bạn di chuyển evenSum để phía trên cùng của lớp, bạn đã không xác định hành vi (vì initializer của nó sử dụng các thành viên chưa được khởi tạo), thậm chí mặc dù trong constructor của bạn, bạn khởi tạo evenAevenB lexically trước evenSum.

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