2012-06-19 36 views
5

Tôi có một lớp cơ sở được gọi là Panel, nơi có một số thông tin về cửa sổ được lưu trữ, sau đó, tôi có các lớp con cho tất cả các nút điều khiển: Nút, Nhãn, v.v. Trong lớp cơ sở, tôi có phương thức virtual void ApplySchemeSettings(Scheme* scheme) { } , được gọi bên trong hàm tạo Panel(Panel* parent). Nhưng thay vì phân lớp, các ApplySchemeSettings từ lớp cơ sở (Panel) đang được gọi.Phương pháp ảo không được gọi là

class Panel 
{ 
    [...] 

public: 
    virtual void ApplySchemeSettings(Scheme* scheme) { }; 

    Panel(Panel* parent) 
    { 
     [...] 

     this->ApplySchemeSettings(scheme()); 
    }; 
} 

class Frame : public Panel 
{ 
    [...] 

public: 
    void ApplySchemeSettings(Scheme* scheme) 
    { 
     this->border = scheme->GetBorder("FrameBorder"); 
    } 
} 

Tôi không thể khai báo ApplySchemeSettings là trừu tượng vì các lớp con được tạo bởi người dùng.

+1

'this-> ApplySchemeSettings (scheme());' loại con trỏ 'this' tại điểm gọi là' Panel * const', vì vậy nó gọi 'Panel :: ApplySchemeSettings'. Đạo đức của câu chuyện không bao giờ gọi hàm ảo từ hàm tạo của lớp cơ sở. –

+0

http://stackoverflow.com/questions/6582239/avoiding-virtual-methods-in-constructor –

+0

http://stackoverflow.com/questions/507043/virtual-function-invocation-from-constructor –

Trả lời

8

Bên trong một hàm tạo, các hàm ảo không hoạt động như bạn mong đợi. Đặc biệt, bất kỳ cuộc gọi nào đến một hàm ảo bên trong một hàm tạo sẽ luôn luôn giải quyết cuộc gọi đến phiên bản của hàm được khai báo bên trong lớp hiện tại. Lý do cho điều này là trong quá trình xây dựng đối tượng, lớp được xây dựng bằng cách đầu tiên có lớp cơ sở nhất được xây dựng, sau đó là lớp con, sau đó là lớp con, v.v. Do đó, trong quá trình xây dựng đối tượng, các lớp dẫn xuất không được khởi tạo cho đến khi cơ sở class constructors kết thúc chạy. Nếu bạn có thể gọi một hàm ảo và giải quyết nó với phiên bản có nguồn gốc bên trong của một hàm tạo lớp cơ sở, bạn sẽ gọi một phương thức trên một lớp chưa được khởi tạo - thậm chí không phải là mặc định các nhà xây dựng cho các thành viên dữ liệu sẽ được gọi đến.

Bạn sẽ cần phải tìm một số cách tiếp cận khác để giải quyết vấn đề này. Bạn có thể, ví dụ, có một cấu trúc hai bước, trong đó bạn gọi một số phương thức init() sau khi gọi hàm tạo. Tuy nhiên, không có cách nào để gọi một cách an toàn phiên bản xuất phát nhất của một hàm ảo từ hàm tạo.

Hy vọng điều này sẽ hữu ích!

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