2013-08-07 41 views
12

Tôi hiểu rằng C++ triển khai các hàm ảo đa hình thời gian chạy thorugh và từ khóa ảo được kế thừa nhưng tôi không thấy sử dụng từ khóa ảo trong lớp dẫn xuất.Sử dụng từ khóa ảo trong C++

ví dụ: Trong trường hợp dưới đây ngay cả khi bạn bỏ từ khóa ảo trong lớp dẫn xuất vẫn ptr-> method() gọi đi đến phương thức :: derived. Vì vậy, những gì thêm từ khóa ảo này đang làm trong lớp dẫn xuất?

#include<iostream> 

using namespace std; 

class base 
{ 
public: 
    virtual void method() 
    { 
     std::cout << std::endl << "BASE" << std::endl; 
    } 
}; 

class derived: public base 
{ 
public: 
    virtual void method() 
    { 
     std::cout << std::endl << "DERIVED" << std::endl; 
    } 
}; 

int main() 
{ 
    base* ptr = new derived(); 
    ptr->method(); 
    return 9; 
} 
+0

Như bạn đã thấy, điều đó là thừa. – BoBTFish

+0

@ Nbr44 bạn sẽ không trả lời được từ bình luận này – triclosan

+0

'virtual' được ngụ ý trong lớp dẫn xuất khi ghi đè một hàm ảo trong lớp cơ sở. C++ 11 cũng giới thiệu từ khóa 'final' để ngăn chặn các lớp thừa kế hơn từ việc thực hiện lại hàm ảo. – dunc123

Trả lời

6

Không có gì. Chỉ để giúp nhắc nhở bạn những chức năng nào là ảo hay không.

8

virtual chỉ cần thiết trong khai báo lớp cơ sở. Đó là tùy chọn trong lớp dẫn xuất (es), và có thể phục vụ chủ yếu như một lời nhắc nhở trong những trường hợp đó.

C++ 11 giới thiệu override để làm cho mọi thứ rõ ràng hơn: nó đánh dấu rõ ràng một phương thức trong lớp dẫn xuất như là ghi đè phương thức virtual của một lớp cơ sở.

21

Nếu phương thức của lớp dẫn xuất khớp với một phương thức ảo của một trong các lớp cơ sở theo tên và chữ ký, và phương thức khớp là ảo, thì phương thức của lớp dẫn xuất cũng trở thành ảo. Vì vậy, về mặt kỹ thuật, không cần đánh dấu các phương thức như «ảo» trong các lớp dẫn xuất. Tuy nhiên, trước khi C++ 11 nó được sử dụng để là một thực hành tốt chỉ vì nó là một gợi ý tuyệt vời cho những người đọc mã (nó có thể được khó khăn để ghi nhớ tất cả các chức năng ảo của lớp cơ sở (es)).

Bắt đầu với C++ 11, có hai từ khóa bổ sung để thực hiện việc này trong các lớp dẫn xuất giúp cả khả năng đọc và mã mạnh mẽ. Họ là «override» và «final». Ví dụ, đặt «override» trong một phương thức của lớp dẫn xuất `đảm bảo rằng một phương thức tương ứng của một lớp cơ sở là, trên thực tế, ảo. Từ khóa «cuối cùng» thực hiện cùng một cộng với từ khóa, nó ngăn cản phương thức này được tiếp tục overriden.

Tôi cũng đã viết về điều này với nhiều lý do thực tế và các ví dụ mã trong blog của tôi, here.

Hy vọng điều đó sẽ hữu ích. Chúc may mắn!

+1

Tôi thích bài đăng trên blog của bạn và tôi có thể bắt đầu sử dụng ghi đè/cuối cùng trên thực tế. – hauron

+0

Định danh đặc biệt 'final' * * không thực hiện tương tự như' override' cộng với ..., nó chỉ ức chế trọng số trong các kiểu có nguồn gốc. Mặc dù nó không có ý nghĩa gì khi tạo một hàm ảo 'final' nếu nó không ghi đè lên một hàm khác (tại sao làm cho nó ảo sau đó?), Trình biên dịch sẽ không xác minh rằng nó ghi đè lên bất cứ thứ gì, vì bạn cần kết hợp' final' và 'ghi đè'. Nghĩa là, 'override' yêu cầu có một ghi đè trong cơ sở,' final' ngụ ý rằng không thể ghi đè trong các kiểu có nguồn gốc. Một cái nhìn lên, cái kia xuống. Kiểm tra cơ sở trong [ideone] (http://ideone.com/2xVsFE) –

+0

@ DavidRodríguez-dribeas: David, nó không ngoại trừ khi bạn cũng đánh dấu chức năng đó là «ảo». Ví dụ, nếu bạn có một số chức năng được đánh dấu chỉ là «cuối cùng» và không có cơ sở ảo cho nó, bạn sẽ nhận được một lỗi như «chỉ các chức năng thành viên ảo có thể được đánh dấu 'cuối cùng'» –

0

từ khóa ảo là tùy chọn trong lớp ổ đĩa vì theo quy tắc khi bạn lái lớp với lớp cơ sở có chức năng ảo và khi bạn ghi đè hàm ảo trong trình biên dịch ổ đĩa, hãy chỉ định rõ từ khóa ảo cùng với hàm. Vì vậy, bạn không cần phải chỉ định rõ ràng từ khóa ảo. Nhưng từ khóa này là cần thiết trong quá trình thừa kế đa cấp.

Ví dụ:

Trong mã của bạn, chúng tôi thêm mã này.

class derived: public base { 
    public: 
     virtual void method() { // In this line virtual keyword is optional. 
       std::cout << std::endl << "DERIVED :: method function" << std::endl; 
     } 

     virtual void display() { 
       std::cout << std::endl << "DERIVED :: display function" << std::endl; 
     } 
    }; 

    class deriveChild: public derived { 
     public: 
      void method() { 
       std::cout << std::endl << "DERIVECHILD :: method" << std::endl; 
      } 

     void display() { 
       std::cout << std::endl << "DERIVECHILD:: display" << std::endl; 
      } 
    }; 

Trong chính() nếu bạn sử dụng mã bên dưới, nó sẽ cung cấp cho bạn đầu ra khác nhau.

base *ptr = new deriveChild(); 
    ptr->method(); // will compile and execute 
    ptr->display(); // will generate error because display() is not part of base class. 

Bây giờ nếu bạn muốn sử dụng display() of deriveChild class thì sử dụng mã này.

derived *ptr = new deriveChild(); 
    ptr->method(); // Compile and Execute 
    ptr->display(); // Compile and Execute 
0

Phương pháp ảo hoàn toàn trong lớp dẫn xuất là ảo trong lớp dẫn xuất, không cần xác định rõ ràng chúng ảo. Nếu bạn khai báo nó sẽ khai báo thừa.

ptr->method(); 

Khi trình biên dịch đi qua tuyên bố trên

-> Nó sẽ cố gắng giải quyết các tuyên bố trên, như là phương pháp() chức năng là ảo, trình biên dịch hoãn việc giải quyết các cuộc gọi mà thời gian để chạy.

-> Khi bạn tạo đối tượng của lớp dẫn xuất tại thời gian chạy, bây giờ trình biên dịch sẽ nhận biết rằng phương thức này là của lớp dẫn xuất.

từ khóa ảo bổ sung này đang làm gì trong lớp dẫn xuất?

Hãy xem xét trường hợp này có thêm một lớp dẫn xuất được gọi là Derived2 biểu mẫu nhận dạng bắt nguồn và nó có phương thức ảo riêng của nó.

class derived2: public derived 
{ 
public: 
    virtual void method() 
    { 
     std::cout << std::endl << "DERIVED2" << std::endl; 
    } 
}; 

Nếu bạn gọi phương thức() trong chính như dưới đây

int main() 
{ 
    base* ptr = new derived2(); 
    ptr->method(); //derived2 class method() will get called 
    return 9; 
} 

Nếu phương pháp() trong derived2 không phải là ảo theo mặc định, bạn sẽ kết thúc gọi teh phiên bản xuất phát của phương pháp() , mất lợi ích của đa hình thời gian chạy.

Do đó các tác giả của C++ đã làm một công việc tuyệt vời ở đây, bằng cách làm cho từ khóa ảo kế thừa phân cấp.

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