2009-09-10 34 views
20

Tôi hy vọng rằng nếu foo được khai báo trong lớp D, nhưng không được đánh dấu là ảo, thì mã sau sẽ gọi việc thực hiện foo trong D (bất kể loại động của d).Trong C++, là một hàm tự động ảo nếu nó ghi đè một hàm ảo?

D& d = ...; 
d.foo(); 

Tuy nhiên, trong chương trình sau, không phải như vậy. Bất cứ ai có thể giải thích điều này? Là một phương pháp tự động ảo nếu nó ghi đè lên một chức năng ảo?

#include <iostream> 

using namespace std; 

class C { 
public: 
     virtual void foo() { cout << "C" << endl; } 
}; 

class D : public C { 
public: 
     void foo() { cout << "D" << endl; } 
}; 

class E : public D { 
public: 
     void foo() { cout << "E" << endl; } 
}; 

int main(int argc, char **argv) 
{ 
     E& e = *new E; 
     D& d = *static_cast<D*>(&e); 
     d.foo(); 
     return 0; 
} 

Đầu ra của chương trình trên là:

E 
+4

Các static_cast là không cần thiết - 'D & d = * static_cast (&e);' là tương đương với 'D & d = e;' do diễn viên tiềm ẩn từ E */E & đến D */D &. –

+0

Trong C++ 11 thêm "override" vào khai báo hàm làm cho nó rõ ràng ý định của bạn để ghi đè lên hàm lớp cơ sở, nó cũng gây ra lỗi từ trình biên dịch trong trường hợp hàm mà bạn khai báo khác với constness từ base. bạn ngạc nhiên trong trường hợp bạn lấy được từ std :: exception ví dụ và khai báo what() non-const) – Ghita

Trả lời

22

Chuẩn 10.3.2 (class.virtual) nói:

Nếu một ảo chức năng thành viên vf được khai báo trong một lớp học cơ sở và trong một lớp học có nguồn gốc, xuất phát trực tiếp hoặc gián tiếp từ cơ sở, một hàm thành viên vf với cùng tên và cùng một danh sách tham số như Base :: vf được khai báo, thì Derived :: vf cũng là virtual (có hoặc không khai báo) và nó ghi đè *

[Chú thích chân trang: Hàm có cùng tên nhưng một danh sách tham số khác (mệnh đề trên) như một hàm ảo không nhất thiết là ảo và không ghi đè lên. Việc sử dụng trình chỉ định ảo trong khai báo hàm ghi đè là hợp pháp nhưng dư thừa (có ngữ nghĩa trống). Kiểm soát truy cập (điều khoản class.access) không được xem xét trong việc xác định trọng số. --- cuối foonote]

17

câu trả lời nhanh có thể không, nhưng câu trả lời đúng là

C++ không biết về chức năng lẩn trốn, vì vậy trọng chức năng ảo không có dấu từ khóa ảo cũng hoạt động ảo.

+11

@Yossarian, đó là lý do tại sao nó được coi là thực hành tốt để khai báo các hàm ảo trong các lớp dẫn xuất như ảo để ý định rõ ràng. thảo luận về điều này trong cuốn sách hiệu quả của C++. –

+0

Tôi đã nghe một nơi nào đó mà không đánh dấu ảo trong phương pháp có nguồn gốc sẽ làm cho họ hầu như cuối cùng. làm cho cấp thứ ba phái sinh một ghi đè không ảo. nhưng tôi thấy rằng trích xuất tiêu chuẩn của Tadeusz đang chứng minh niềm tin này sai vì từ ngữ 'gián tiếp', phải không? –

+2

@ v.oddou "Tôi đã nghe một nơi nào đó" rằng mọi thứ mọi người đã "nghe ở đâu đó" thường là sai. ;-) Miễn là có một hàm có cùng chữ ký được đánh dấu 'ảo' _somewhere_ cao hơn trong cấu trúc phân cấp, thì bất kỳ hàm có nguồn gốc nào có cùng chữ ký đều là ghi đè. 'Khoảng trống' trong việc tuyên bố bao gồm 'ảo' không có liên quan, như một lần nữa, từ khóa có ngữ nghĩa trống sau khi xuất hiện cơ bản nhất của nó. –

0

Bạn không tạo bất kỳ bản sao nào của đối tượng của e và đặt nó vào d. Vì vậy, d.foo() tuân theo hành vi đa hình bình thường và các phương thức lớp dẫn xuất. Một phương thức được khai báo là ảo trong lớp cơ sở sẽ tự động ảo trong lớp dẫn xuất.

-1

Đầu ra ("E") hoạt động chính xác như mong đợi nó hoạt động.

Lý do: Loại động (tức là thời gian chạy) của tham chiếu đó là E. Bạn đang thực hiện một upcast tĩnh cho D, nhưng điều đó không thay đổi loại thực tế của đối tượng của khóa học.

Đó là ý tưởng rất quan trọng đằng sau các phương thức ảo và công văn động: Bạn thấy hành vi của loại bạn đã khởi tạo, đó là E, trong trường hợp này.

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