2013-03-15 16 views
1

我有一個類中聲明如下:對C++中的非純虛擬類感到困惑,它們的用途是什麼?

class TestFoo { 
public: 
    TestFoo(); 
    virtual void virtualFunction(); 
    void nonVirtualFunction(); 
}; 

,我嘗試實施這種方式

TestFoo::TestFoo(){} 
void TestFoo::nonVirtualFunction(){} 

其上編譯返回錯誤:

undefined reference to vtable for TestFoo 

我想:

TestFoo::TestFoo(){} 
void TestFoo::nonVirtualFunction(){} 
void TestFoo::virtualFunction(){} 

其編譯好的這對解答這些職位是一致的:

Undefined reference to vtable

undefined reference to vtable

什麼讓我困惑的是,我想聲明一個虛函數的整點是,我不需要來定義它。在這個例子中,我不打算創建TestFoo的任何實例,而是創建從TestFoo繼承的(具體)類的實例。但是,我仍然想爲TestFoo的每個子類定義函數nonVirtualFunction。

我沒有正確的做對嗎?

謝謝!

回答

1

你的描述完全符合抽象類的情況。聲明你的虛函數爲:

virtual void VirtualFunction() = 0; 

這意味着你沒有在這個類中實現這個函數。結果,班級變得抽象。也就是說,這個類的裸露對象不能被實例化。

此外,你應該提供一個虛擬析構函數。

更新:一些澄清...

的語言讓你重新定義一個非虛擬函數。雖然,錯誤版本可能被稱爲在某些情況下:

derived D; // rB is a reference to base class but it 
base & rB=D; // points to an object of the derived class 

rB.NonVirtualFunction(); // The base-class version is called 

爲此,重新定義一個非虛擬函數強烈時下勸阻。請參閱Scott Meyers的「Effective C++,第三版:55個改進程序和設計的具體方法」,第36項:「不要重新定義繼承的非虛函數。」

另請參見項目7:「在多態基類中聲明析構函數虛擬」。舉個例子:

base * pB = new derived; 
delete pB;    // If base's destructor is not virtual, 
          // ~derived() will not be called. 

如果你想知道爲什麼不是萬能的默認虛擬,原因是調用虛函數比調用非虛擬一個稍微慢一些。哦,虛擬函數類的對象每個都佔用幾個字節。

7

the whole point of declaring a virtual function is that I would not need to define it

不完全,它說「我可能想用派生類中的其他東西替換這個函數的實現。」

我可能誤解了你的問題,但你似乎暗示你不認爲你可以在C++中定義純粹的虛擬成員函數。您可以聲明一如下。

virtual void virtualFunction() = 0; 

通常情況下,一個純虛函數不會定義,當然你也可以。這就是說「這個函數沒有默認的實現,因爲它並不總是有意義的,但我會給你提供一個你可以選擇的實現。」

順便說一句,如果一個類有任何虛函數,你也應該定義一個虛析構函數,因爲它是完全合法的(而且經常推薦)有一個基類(智能)指針派生類 - 沒有虛擬析構函數,對象可能不是delete d正確。

+0

其實你必須定義一個虛擬析構函數,否則你可能會得到這個「未定義的引用vtable」的錯誤。 – Arne 2013-03-15 08:18:55

+0

@Arne爲什麼?_____ – 2013-03-15 08:19:47

+0

@阿爾納可以肯定這是沒有根據的。 – 2013-03-15 08:20:27

3

... I thought the whole point of declaring a virtual function is that I would not need to define it ...

對於設施你有一個功能叫做純虛方法:

virtual void virtualFunction() = 0; // no linking error now 

需要注意的是,一個virtual方法無法仍未得到執行。原因是每virtual方法宣稱class身體內必須有vtable條目。未能找到其正文會導致鏈接錯誤。

目的這個限制的:
除非一類是抽象的 - 即它至少有一個虛函數 - 有沒有辦法可以保證你不打算申報TestFoo對象編譯器。當你做以下事情時會發生什麼:

DerivedOfTestFoo obj1; 
TestFoo obj2 = obj1, *p = &obj2; // object slicing 
p->virtualFunction(); // where is the body? 

其他情況;在構造函數中沒有virtual機制:

TestFoo::TestFoo() { 
    this->virtualFunction(); // where is the body? 
} 

我們可以得出這樣的結論,編譯器遵循規則,「最好是安全比遺憾」。 :)

+0

也許我誤解了,但我確定'TestFoo obj2'對抽象類是非法的。 – 2013-03-15 08:26:21

+1

@AlexChamberlain,'TestFoo'只有在它內部至少有一個純'virtual'方法時纔會變成抽象的,但這不是OP的問題。此外,我舉一個例子,假設如果OP的請求會被C++語言所接受,那麼會發生什麼。實際上它會導致鏈接器錯誤。 – iammilind 2013-03-15 08:28:13

+0

我明白你的意思,但我相當肯定這不是你的答案所說的。 – 2013-03-15 08:29:52

0

如果你想讓這個虛函數爲純虛函數,不想定義它,那麼virtual void virtualFunction()= 0;