2011-07-22 30 views
5

Đọc rằng bạn có thể có final virtual functions trong C++ 0x Tôi hơi bối rối. Sự khác biệt khi bỏ qua cả hai công cụ sửa đổi ở vị trí đầu tiên là gì?chức năng ảo cuối cùng trong C++ 0x

+0

xem xét, trong ví dụ này, nếu 'Base' được kế thừa từ một lớp khác khai báo phương thức 'f' gốc ban đầu. –

Trả lời

10

Sự khác biệt xảy ra không phải là cơ sở sử dụng nó, mà là nguồn gốc.

class Base { 
    virtual void foo() = 0; 
}; 
class Derived : Base { 
    void foo() {} 
    // Still virtual because it's virtual in base- no way to "un-virtual" it 

    virtual void foo() final {} 
    // Now un-overridable. 
}; 

Hãy nghĩ rằng nó không phải là ngăn chặn ghi đè, nhưng ngăn ngừa ghi đè "bất kỳ" nào khác.

+0

Cảm ơn! Nó không rõ ràng với tôi, rằng ảo được thực hiện thông qua toàn bộ hệ thống phân cấp. –

1

Khi tôi lần đầu tiên đi qua việc sử dụng các từ khóa final kết hợp với virtual trong C++, tôi đã tự hỏi điều tương tự:

Nếu tuyên bố một phương pháp virtual làm cho nó thừa kế và overridable, và tuyên bố một phương pháp final ngăn không cho phương thức đó bị ghi đè, không khai báo phương thức cả hai là một mâu thuẫn?

Tôi nghĩ rằng hiện tại accepted answer cho câu hỏi này là tốt, nhưng tôi muốn xây dựng dựa trên nó nhiều hơn một chút dựa trên những gì tôi thấy.

Hãy xem xét các lớp sau đây:

class A { 
    public: 
     void hide_me(); 
     virtual void override_me(); 
     virtual void cant_override_me() final; 
}; 

Điều quan trọng cần nhận ra là ba lời tuyên bố phương pháp đều khác biệt và ý nghĩa khác nhau.

Đầu tiên:

void hide_me(); 

là không ảo và do đó, theo định nghĩa, không thể được ghi đè.

Thứ ba:

virtual void cant_override_me() final; 

được khai báo final, và do đó không thể được ghi đè, cũng theo định nghĩa.

Sự khác biệt là kể từ khi hide_me là không ảo, trọng nó là unapplicable, trong khi bạn có thể nghĩ cant_override_me như đủ điều kiện để được ghi đè (vì nó là virtual,) nhưng nó cũng đã trọng bị vô hiệu hóa do công cụ sửa đổi final. Nói cách khác, ghi đè không áp dụng cho các phương thức không được khai báo là virtual, nhưng nó áp dụng cho các phương thức virtual, bạn không thể ghi đè chúng nếu chúng cũng được khai báo final.

Bây giờ hãy xem xét một lớp trẻ:

class B: public A { 
    public: 
     void hide_me(); // this hide's A's definition of "hide_me()"; this is not overriding. 
     void override_me(); // implicit "virtual" 
     //void cant_override_me(); // implicit "virtual"; compilation fails 
}; 

Bạn thể xác định lại hide_me() cho lớp B, nhưng điều này chỉ là quá tải hoặc hiding, vì thế mà tên hàm. B vẫn có thể truy cập phương thức hide_me của A qua A::hide_me(), nhưng một người khác có tham chiếu đến B được khai báo là B, tức là:

B *my_b = new B(); 

phải truy cập A 's bây giờ ẩn nghĩa về hide_me qua my_b->A::hide_me().

Bạn không thể cung cấp định nghĩa lại cant_override_me() trong B.

Là một ví dụ đầy đủ, đây là một định nghĩa lại nhẹ của chương trình để giúp minh họa cho những gì đang xảy ra:

#include <cstdio>  
class A { 
    public: 
     inline void hide_me() { 
      printf("a hide_me\n"); 
     } 
     virtual void override_me(); 
     virtual void cant_override_me() final; 
}; 

class B: public A { 
    public: 
     inline void hide_me() { 
      printf("b hide_me\n"); 
     } 
     void override_me(); 
     inline void foo() { 
      A::hide_me(); 
     } 
     // can't override cant_override_me 
}; 

void A::override_me() { 
    printf("a override_me\n"); 
} 

void A::cant_override_me() { 
    printf("a cant_override_me\n"); 
} 

void B::override_me() { 
    printf("b override_me\n"); 
} 

int main (int argc, char *argv[]) { 
    A *a = new A(); 
    A *ab = new B(); 
    B *b = new B(); 

    a->hide_me(); 
    ab->hide_me(); 
    b->hide_me(); 
    b->A::hide_me(); 

    printf("---\n"); 

    a->override_me(); 
    ab->override_me(); 
    b->override_me(); 
    b->A::override_me(); 
} 

Các đầu ra chương trình

a hide_me 
a hide_me 
b hide_me 
a hide_me 
--- 
a override_me 
b override_me 
b override_me 
a override_me 
Các vấn đề liên quan