2011-12-27 59 views
7

是否有必要爲虛擬功能定義?虛擬函數是否應該有一個定義?

考慮下面這個示例程序:

#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; 
} 

這給了鏈接錯誤:

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

我沒有在基類中的虛函數的定義。即使我沒有明確調用虛擬函數,爲什麼會發生此錯誤?

我發現有趣的是,如果我沒有實例化類derived的對象,鏈接錯誤不再存在。爲什麼是這樣?實例化與上面的鏈接錯誤有什麼關係?

+1

重新編輯:如果您沒有實例化一個'derived'或'base',爲什麼鏈接器必須對這兩個類中的任何方法做任何事情?如果這些類沒有被引用,鏈接器沒有理由甚至試圖在對象文件中查找它們。 (除非你正在建立一個圖書館。) – Mat 2011-12-27 08:48:42

+0

@Mat:我同意:) – 2011-12-27 08:55:39

回答

10

的ISO C++標準指定不在純虛擬的類的所有虛擬方法必須被定義。

參考:

C++ 03標準:10.3虛函數[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).

因此,無論你應該做的函數純虛或爲它提供一個定義。

如果您使用的是gcc,如果您未能遵循此標準規範,則可能會出現一些奇怪的錯誤。所述gcc faq doccuments它,以及:

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

太好了!優秀:) – 2011-12-27 07:47:03

3

您或者需要提供一個定義,或者將其標記爲抽象/純粹的。

void virtual virtualfunc() = 0; 
+0

簡明而且幾乎說明了一切。 – Gravity 2011-12-27 07:33:04

8

您需要提供一個虛函數的實現(其默認行爲),除非你定義的函數是「純虛」。

所以,你的例子是:

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

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

是的,你需要一個身體,但也許你指的是被稱爲純虛函數,它不需要基類中的定義。

的語法來定義這些如下:

void virtual virtualfunc() = 0; 
1

在回答關於vtable中的錯誤:在這種情況下,虛擬命令告訴C++,以產生在基類的方法的虛擬表。通過這種方式,當您使用多態性時,C++能夠在運行時使用具有相同名稱的派生類中的方法替換基類虛擬方法。這個錯誤告訴用戶這個替換是不可能的。要解決這個錯誤,你需要實現這個方法,或者在定義的末尾添加「= 0」來將它設置爲純虛擬。

迴應編輯:當您將對象實例化爲基類時,您沒有收到錯誤的原因是因爲基類不需要訪問虛擬表。另一方面,如果你真的嘗試使用這種方法,你應該得到一個錯誤,因爲沒有實現存在。換句話說,即使你可以實例化一個基類的對象,但它不是一個完整的類。

+1

這是深刻的原因! – selfboot 2016-09-12 14:02:28

相關問題