2009-06-10 36 views
28

Trong C++, nó là hợp pháp để cung cấp cho một thực hiện một chức năng ảo tinh khiết:Trong những trường hợp nào thuận lợi để thực hiện một chức năng ảo thuần túy?

class C 
{ 
public: 
    virtual int f() = 0; 
}; 

int C::f() 
{ 
    return 0; 
} 

Tại sao bạn đã bao giờ muốn làm điều này?

câu hỏi liên quan: Các C++ faq lite chứa một ví dụ:

class Funct { 
public: 
    virtual int doit(int x) = 0; 
    virtual ~Funct() = 0; 
}; 

inline Funct::~Funct() { } // defined even though it's pure virtual; it's faster this way; trust me 

Tôi không hiểu tại sao các destructor được tuyên bố thuần ảo và sau đó thực hiện; và tôi không hiểu bình luận tại sao điều này nên nhanh hơn.

Trả lời

23

Trình phá hủy được khai báo phải luôn được triển khai khi triển khai sẽ gọi chúng là một phần của sự phá hủy đối tượng dẫn xuất.

Các chức năng ảo thuần túy khác có thể được triển khai nếu chúng cung cấp chức năng phổ biến hữu ích nhưng luôn cần phải chuyên môn hóa. Trong trường hợp, triển khai lớp học thường được thừa kế sẽ thực hiện cuộc gọi rõ ràng để thực hiện cơ sở:

void Derived::f() 
{ 
    Base::f(); 

    // Other Derived specific functionality 
} 

Thông thường, bạn thực hiện một destructor ảo nếu bạn cần phải thực hiện một abstract class (tức là ngăn chặn các trường hợp không có nguồn gốc từ từ được tạo ra) nhưng lớp không có chức năng nào khác là tự nhiên thuần ảo. Tôi nghĩ rằng 'tin tưởng tôi nhanh hơn' là đề cập đến thực tế là bởi vì destructors được gọi là một phần của đối tượng có nguồn gốc làm sạch không cần phải sử dụng một cơ chế tra cứu vtable, việc thực hiện nội tuyến có thể được tận dụng, không giống như các cuộc gọi chức năng ảo điển hình .

4

Nếu bạn có chức năng phổ biến đến mức lớp học có thể sử dụng. Nhưng họ cần làm công việc khác.

Vì vậy, các lớp được thừa kế thực hiện các chức năng ảo và gọi phiên bản cơ sở cơ bản:

class X: public C 
{ 
    public: 
     virtual int f() 
     { 
      return C::f() + 1; // I am +1 over my parent. 
     } 
}; 
0

Bởi vì nó được coi là bệnh thành lập để viết:

class Funct { 
public: 
    virtual int doit(int x) = 0; 
    virtual ~Funct() = 0 {}; 
}; 

Destructor vẫn sẽ được gọi nếu bạn xuất phát từ lớp này. Khai báo tất cả các phương thức ảo thuần túy chỉ dành cho sự rõ ràng. Bạn cũng có thể viết như thế này:

class Funct { 
public: 
    virtual int doit(int x) = 0; 
    virtual ~Funct() {}; 
}; 

Lớp học vẫn sẽ trừu tượng vì ít nhất một phương pháp là ảo thuần. Destructor cũng vẫn là inline.

2

G'day,

Về việc cung cấp một cài đặt mặc định cho một hàm thành viên khai báo trong một lớp cơ sở, lý do duy nhất tôi có thể nghĩ đến lúc này là nơi bạn muốn cung cấp một cài đặt mặc định của các hành vi như một lựa chọn thực hiện có thể cho một người chuyên về lớp cơ sở.

Tác giả của lớp dẫn xuất có thể chọn sử dụng triển khai mặc định do tác giả lớp cơ sở cung cấp thay vì thêm triển khai chuyên ngành của riêng họ. Đây là trường hợp mọi người phản đối việc có các chức năng riêng biệt để cung cấp một giao diện và thực hiện mặc định hành vi nhưng họ vẫn muốn tách giữa triển khai mặc định và giao diện được liên kết.

Ah, vừa xem bài đăng của @Martin York cung cấp ví dụ.

Thực ra, Scott Meyers thảo luận về điều này trong cuốn sách "Hiệu quả C++" của mình. Đó là mục 36 trong ấn bản đầu tiên.

HTH

cổ vũ,

4

Chỉ cần phát hiện ra rằng Herb Sutter đã trả lời phần đầu của câu hỏi này trong Guru of the Week #31 mình.

0

Về tốc độ của trình phá hủy ảo, điều này là do hàm hủy được định nghĩa trong tệp cpp chứ không phải tiêu đề. Nó có nhiều hơn để làm với kích thước hơn tốc độ. Nó được giải thích chi tiết trong "Thiết kế phần mềm C++ quy mô lớn". Thật không may tôi không thể nhớ tất cả các chi tiết, nhưng tôi nghĩ rằng các chức năng ảo nội tuyến được xác định nhiều lần trong vtable.

Có một cuộc thảo luận tại đây: Are inline virtual functions really a non-sense?

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