2010-01-23 21 views
11

Khi tôi đọc hiệu quả C++, nó nói, không bao giờ xác định lại hàm không phải ảo trong C++.xác định lại hàm không phải ảo trong C++

Tuy nhiên, khi tôi thử nghiệm, mã bên dưới biên dịch chính xác. Vậy vấn đề là gì? Đó là một sai lầm hoặc chỉ là một thực hành xấu?

class A { 

    public: 
    void f() { cout<<"a.f()"<<endl;}; 
}; 

class B: public A { 
    public: 
    void f() { cout<<"b.f()"<<endl;}; 
}; 


int main(){ 

    B *b = new B(); 
    b->f(); 
    return 0; 
} 

Trả lời

24

Xác định lại chức năng không phải là ảo miễn là bạn không phụ thuộc vào hành vi gửi ảo.

Tác giả của cuốn sách sợ rằng bạn sẽ vượt qua B* của bạn đến một chức năng mất A* và sau đó sẽ khó chịu khi kết quả là một cuộc gọi đến phương thức cơ sở, không phải là phương pháp có nguồn gốc.

+2

Câu trả lời đáng yêu! Ngắn gọn, cho điểm, và cho thấy cách lập trình cảm xúc. – DarenW

+0

Tôi không đồng ý, tác giả Scott Meyers chỉ ra rằng thừa kế công khai thiết lập một sự bất biến về chuyên môn hóa cho lớp b. Hơn nữa, việc sử dụng lớp là khó hiểu khi hành vi của hành vi f() phụ thuộc vào định nghĩa con trỏ không phải là định nghĩa đối tượng. Ví dụ: B x; A * ptr = & x; ptr-> f() // gọi phiên bản lớp A của f() và không phải là phiên bản lớp B của f() và điều đó gây nhầm lẫn. – TheChrisONeil

7

Hãy thử điều này:

int main(){ 
    A *b = new B(); 
    b->f(); 
    return 0; 
} 

Tôi nghĩ rằng câu trả lời sẽ rõ ràng khi bạn xem kết quả ;-).

Không ảo, cơ chế kết buộc muộn sẽ không được sử dụng, do đó hàm được xác định cho loại con trỏ đó sẽ được sử dụng, không phải chức năng bị ràng buộc trễ mà bạn muốn để gọi. Điều này dẫn đến tấn lỗi có thể theo dõi được.

Do đó, những gì bạn đang làm là tạo ra một chức năng mới. Nó có thể là những gì bạn dự định, nhưng ai đó đọc mã của bạn sau đó có thể mong đợi mã ở trên hoạt động với sự ràng buộc muộn. Rất bối rối.

Một trong những tính năng mà tôi thực sự muốn nhìn thấy là một cảnh báo trong trường hợp này, với một "xác định lại" từ khóa để ngăn chặn nó, nhưng giấc mơ là giấc mơ, và thực tế là thực tế -_-

2

Vấn đề là nếu bạn, ví dụ, có một danh sách các con trỏ đến lớp cơ sở (List<A *> list) và sau đó gọi f(), phương pháp được triển khai lại trong B sẽ không được gọi.

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