2011-12-27 24 views
7

Có cần thiết phải có định nghĩa cho một chức năng ảo không?Một chức năng ảo về cơ bản có định nghĩa không?

xem xét chương trình mẫu này dưới đây:

#include <iostream> 

using namespace std; 

class base 
{ 
    public: 
     void virtual virtualfunc(); 
}; 

class derived : public base 
{ 
    public: 
    void virtualfunc() 
    { 
     cout << "vf in derived class\n"; 
    } 
}; 

int main() 
{ 
    derived d; 
    return 0; 
} 

này cung cấp cho các liên kết lỗi:

In function base::base() :: undefined reference to vtable for base

Tôi không có định nghĩa cho hàm ảo trong lớp cơ sở. Tại sao lỗi này xảy ra mặc dù tôi đã không gọi hàm ảo một cách rõ ràng?

Điều thú vị mà tôi thấy là nếu tôi không khởi tạo đối tượng của lớp derived, lỗi liên kết sẽ không còn ở đó nữa. Tại sao điều này? Điều gì đã instantiation đã làm với các lỗi liên kết ở trên?

+1

Chỉnh sửa lại: nếu bạn không khởi tạo một 'nguồn gốc' hoặc' cơ sở', tại sao trình liên kết phải làm bất kỳ điều gì với bất kỳ phương thức nào từ hai lớp đó? Nếu các lớp không được tham chiếu, trình liên kết không có lý do gì để thậm chí cố tìm chúng trong các tệp đối tượng. (Trừ khi bạn đang xây dựng một thư viện.) – Mat

+0

@Mat: Tôi đồng ý :) –

Trả lời

10

C++ chuẩn ISO quy định rằng tất cả các phương pháp ảo của một lớp mà không phải là thuần ảo phải được xác định.

tham khảo:

C++ 03 Tiêu chuẩn: 10,3 chức năng ảo [class.virtual]

A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required (3.2).

Vì vậy, hoặc là bạn nên thực hiện các chức năng thuần túy ảo hoặc cung cấp một định nghĩa cho nó.

Nếu bạn đang sử dụng gcc, Bạn có thể gặp phải một số lỗi lạ nếu bạn không tuân theo đặc điểm kỹ thuật tiêu chuẩn này. Các gcc faq doccuments nó là tốt:

The ISO C++ Standard specifies that all virtual methods of a class that are not pure-virtual must be defined, but does not require any diagnostic for violations of this rule [class.virtual]/8 . Based on this assumption, GCC will only emit the implicitly defined constructors, the assignment operator, the destructor and the virtual table of a class in the translation unit that defines its first such non-inline method.

Therefore, if you fail to define this particular method, the linker may complain about the lack of definitions for apparently unrelated symbols. Unfortunately, in order to improve this error message, it might be necessary to change the linker, and this can't always be done.

The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7 .

+0

Tuyệt vời !. Tuyệt vời :) –

3

Bạn cần cung cấp định nghĩa hoặc đánh dấu là trừu tượng/thuần túy.

void virtual virtualfunc() = 0; 
+0

Ngắn gọn và khá nhiều nói tất cả. – Gravity

8

Bạn cần cung cấp chức năng ảo (với hành vi mặc định) trừ khi bạn xác định hàm là "thuần ảo".

Vì vậy, ví dụ bạn có thể là:

class base 
{ 
    public: 
     void virtual virtualfunc() {} //intentionally do nothing; 
}; 

hoặc

class base 
{ 
    public: 
     void virtual virtualfunc()=0; //pure virtual; 
}; 
0

Có bạn sẽ cần một cơ thể, nhưng có lẽ những gì bạn đang đề cập đến được gọi là một hàm ảo thuần túy, mà sẽ không cần một định nghĩa trong lớp cơ sở.

Cú pháp để xác định những người là như sau:

void virtual virtualfunc() = 0; 
1

Để đối phó với các lỗi về vtable: lệnh ảo trong trường hợp này nói với C++ để tạo ra một bảng ảo của phương pháp trong các lớp cơ sở. Bằng cách này khi bạn sử dụng đa hình, C++ có thể thay thế các phương thức ảo lớp cơ sở bằng các phương thức từ lớp dẫn xuất có cùng tên trong suốt thời gian chạy. Lỗi này cho người dùng biết rằng việc thay thế này là không thể. Để khắc phục lỗi này, bạn sẽ cần triển khai phương thức hoặc đặt phương thức đó là ảo thuần túy bằng cách thêm "= 0" ở cuối định nghĩa.

Để phản hồi chỉnh sửa: Lý do bạn không gặp lỗi khi bạn khởi tạo đối tượng làm lớp cơ sở là vì lớp cơ sở không cần truy cập bảng ảo. Mặt khác, nếu bạn thực sự cố gắng sử dụng phương pháp này, bạn sẽ nhận được một lỗi vì không có triển khai thực hiện. Nói cách khác, ngay cả khi bạn có thể khởi tạo một đối tượng của lớp cơ sở, nó không phải là một lớp hoàn chỉnh.

+1

Đây là lý do sâu sắc !! – selfboot

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