2013-07-16 26 views
5

Tôi mới sử dụng C++ và tôi vừa học về các hàm ảo.Nguyên tắc của các hàm ảo trong C++

Tôi nghe nói rằng trình biên dịch tạo ra vtable, có chứa địa chỉ hàm ảo của lớp, khi tôi định nghĩa một hàm ảo. Khi một hàm ảo được gọi, trình biên dịch tìm địa chỉ của nó bằng cách sử dụng vtable.

Tôi thực sự không thể hiểu lý do tại sao trình biên dịch không gọi hàm của cá thể lớp mà đối tượng thuộc về.

Tại sao trình biên dịch sử dụng vtable? Bạn có thể giải thích điều này?

+0

Lý do sử dụng vtable là khi một lớp dẫn xuất thực hiện lại một hàm ảo, trong quá trình khởi tạo của lớp dẫn xuất, vtable được cập nhật để trỏ đến việc thực thi có nguồn gốc thay cho cơ sở. – Borgleader

+5

Hai từ: * công văn động *. Mặc dù có những giải thích tốt dưới đây, bạn cần ít nhất là nghe thuật ngữ chính xác. –

Trả lời

9

Tôi thực sự không thể hiểu lý do tại sao trình biên dịch không gọi hàm của cá thể lớp thuộc về?

Đó là những gì trình biên dịch thực hiện - đảm bảo rằng chương trình của bạn gọi hàm của lớp mà cá thể đó thuộc về. Từ khóa ở đây là dụ: kiến ​​thức về lớp của cá thể không có sẵn tại thời gian biên dịch.

Hãy xem xét ví dụ đơn giản này:

struct Dude { 
    virtual void howdy() = 0; 
}; 
struct Bob : public Dude { 
    virtual void howdy() { cout << "Hi, Bob!" << endl; } 
}; 
struct Moe : public Dude { 
    virtual void howdy() { cout << "Hi, Moe!" << endl; } 
}; 
// Note the pass by reference below: passing by reference or by pointer, 
// but not by value, is important for achieving polymorphic behavior. 
void say_hi(Dude& dude) { 
    dude.howdy(); // <<== Here is the tricky line 
} 
int main(int argc, char* argv[]) { 
    Bob b; 
    Moe m; 
    Dude *d = rand() & 1 ? (Dude*)&b : &m; 
    say_hi(*d); 
} 

Lưu ý dòng khó khăn: trình biên dịch có thể hiện, nhưng nó không biết lớp. Trên thực tế, nó là loại biết lớp, nhưng không phải là một trong những cụ thể nhất. Kiến thức của trình biên dịch có lúc biên dịch là đủ để biết rằng có một hàm gọi là howdy, nhưng không đủ để quyết định cái nào trong số một số khả năng sẽ là một trong những hàm gọi trong thời gian chạy.

Đây là nơi vtables đến để giải cứu: trình biên dịch biết rằng các lớp con của Dude sẽ có một con trỏ đến hàm howdy được nhúng ở đâu đó vào vtable của chúng. Đó là tất cả những gì họ cần biết khi biên dịch! Họ chèn một cuộc gọi ảo tìm kiếm con trỏ hàm trong thời gian chạy, đạt được hành vi mà bạn mong đợi (từ ưa thích cho loại hành vi đó là "đa hình"). Dưới đây là một số demo of this program chạy trên ideone.

+0

Thực ra, 'howdy' có thể là' const', và bạn có thể chuyển một tham chiếu 'const' sang' say_hi' ... nhưng tôi chỉ là nitpicking. : P –

+1

@DanielKamilKozar Tất nhiên, đó là những gì tôi muốn làm trong một vấn đề sản xuất. Tuy nhiên, đó không phải là điều cần thiết để hiểu các nguyên tắc cơ bản của đa hình, vì vậy tôi đã rút gọn ví dụ về mức tối thiểu của nó. – dasblinkenlight

+3

Ví dụ của bạn là chính xác nhưng có thể không lý tưởng: Tôi biết ít nhất một trình biên dịch sẽ giải quyết các cuộc gọi tại thời gian biên dịch. do_something(); 'là tốt hơn một chút bởi vì nó tránh được" vấn đề "và, theo ý kiến ​​của tôi, là anyways minh họa hơn. –

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