2010-10-21 40 views
18

Tôi có một câu hỏi về việc khởi tạo các thành viên kế thừa trong hàm tạo của lớp dẫn xuất. mã ví dụ:C++: Khởi tạo trường kế thừa

class A 
    { 
public: 
    int m_int; 
    }; 

class B: public A 
    { 
public: 
    B():m_int(0){} 
    }; 

Mã này mang lại cho tôi kết quả như sau:

In constructor 'B::B()': Line 10: error: class 'B' does not have any field named 'm_int'

(thấy http://codepad.org/tn1weFFP)

Tôi đoán lý do tại sao điều này xảy ra? m_int nên thành viên của B, và tầng lớp phụ huynh A nên đã được khởi tạo khi khởi tạo của m_int trong B xảy ra (vì nhà xây dựng mẹ chạy trước khi khởi tạo thành viên của lớp được thừa kế). Đâu là một sai lầm trong lý luận của tôi? Điều gì thực sự xảy ra trong mã này?

EDIT: Tôi biết các khả năng khác để khởi tạo thành viên này (hàm tạo cơ sở hoặc gán trong hàm khởi tạo), nhưng tôi muốn hiểu tại sao nó lại bất hợp pháp theo cách tôi thử? Một số tính năng ngôn ngữ C++ cụ thể hoặc như vậy? Vui lòng chỉ cho tôi một đoạn trong tiêu chuẩn C++ nếu có thể.

Trả lời

18

Bạn cần phải thực hiện một constructor cho A (nó có thể được bảo vệ vì vậy chỉ B có thể gọi nó) mà khởi m_int cũng giống như bạn có, sau đó bạn gọi :A(0), nơi bạn có :m_int(0)

Bạn cũng có thể chỉ cần đặt m_int = 0 trong cơ thể của nhà xây dựng B. Nó có thể truy cập (như bạn mô tả) nó chỉ không có sẵn trong cú pháp hàm dựng đặc biệt.

class A{ 
public: 
    A() : m_int(0); 
    int m_int; 
}; 

để m_int được khởi tạo trong địa điểm chính xác:

+5

Đây là câu trả lời hay nhưng tôi chỉ muốn thêm một số giải thích. Khi bạn sử dụng toán tử:, bạn đang nói với trình biên dịch rằng trước khi nó thực hiện bất cứ điều gì khác, nó sẽ chạy các hướng dẫn này. Về cơ bản bạn đang thiết lập một biến trước khi constructor cha (hoặc bất cứ điều gì khác) đã chạy. Do đó biến không tồn tại. : A(), m_int (0) cũng sẽ hoạt động.Theo mặc định, nếu bạn không sử dụng:, trình biên dịch sẽ chạy hàm tạo của lớp cơ sở. Nói cách khác, nếu bạn không làm gì thì C++ sẽ làm những thứ mặc định cho bạn, nếu bạn bắt đầu chỉ định mọi thứ, nó sẽ cho bạn biết bạn đang làm gì. –

+0

Hmmm ... Theo như tôi biết hàm tạo của lớp cha luôn luôn chạy trước bất kỳ khởi tạo nào khác và do đó biến 'm_int' đã tồn tại khi tôi đang cố gắng khởi tạo nó. Vì vậy, đây không phải là vấn đề ... – Haspemulator

+0

@ Haspemulator Vâng, nó đã tồn tại nhưng đó là lý do tại sao bạn nhận được lỗi. Nó đã được khởi tạo mặc định bởi hàm tạo của A. Bạn không thể khởi tạo lại một biến trong hàm tạo của B. Bạn có thể chỉ định lại như Ben Jackson nêu trên ('m_int = 0') và đó là về nó tại thời điểm đó. – wheaties

4

gì bạn muốn điều này là.

Edit:

Từ một bình luận trên, lý do trình biên dịch phàn nàn khi bạn cố gắng để khởi tạo biến m_int trong B là nó đã được khởi tạo bởi các nhà xây dựng của A. Tức là, bạn không thể khởi tạo lại thứ gì đó, chỉ gán lại. Vì vậy, bạn có thể chỉ định lại như Ben Jackson đã nêu ở trên hoặc bạn có thể khởi tạo ở vị trí thích hợp.

4

Để xây dựng một thể hiện của lớp B, trước tiên bạn khởi tạo một thể hiện của lớp A. Trong thời gian đó, m_int được khởi tạo. Sau khi intialization rằng constructor của b được gọi, vì vậy bạn không thể khởi tạo lại m_int. Nếu đó là mục tiêu của bạn thì bạn có thể thực hiện một constructor cho A mà phải mất một int và sau đó gọi rằng trong danh sách khởi B 's:

class A 
{ 
public: 
    A(int x): m_int(x) {} 
    int m_int; 
}; 

class B: public A 
{ 
public: 
    B(): A(2) {} 
}; 
+0

Có lý do nào không có trong danh sách khởi tạo không? Tôi nhận thức được các khả năng khác để khởi tạo thành viên này (constructor cơ sở hoặc gán trong constructor có nguồn gốc), nhưng tôi muốn hiểu tại sao nó lại bất hợp pháp theo cách tôi thử? Một số tính năng ngôn ngữ C++ cụ thể hoặc như vậy? Vui lòng chỉ cho tôi một đoạn trong tiêu chuẩn C++ nếu có thể. – Haspemulator

+0

Đó là hai điều - các lớp dẫn xuất khởi tạo các lớp cơ sở của chúng trước tiên, và các thành viên được khởi tạo theo thứ tự chúng được khai báo, không phải thứ tự chúng xuất hiện trong danh sách khởi tạo. Do đó các thành viên của cơ sở được khởi tạo đầu tiên và bạn không thể khởi tạo lại chúng. –

0

làm một constructor A và sử dụng B(): A (2) {} insteed của B(): m_int (0) {} hoạt động của nó.