2011-03-18 25 views
1

我有一個類,它從具有純虛擬函數的類繼承。當缺少未使用的純虛擬方法的實現時,鏈接失敗

現在我需要添加另一個類,它不需要某種方法。我有一個想法沒有實現這個方法,而不是總在下面的例子中拋出一個異常時,調用此方法,如:

#include <iostream> 

class ibase { 
    public: 
     virtual void foo() = 0; 
     virtual void boo() = 0; 
}; 

class base1 : public ibase { 
    public: 
     virtual void foo(){ std::cout<<"base1::foo"<<std::endl; } 
     virtual void boo(){ std::cout<<"base1::boo"<<std::endl; } 
}; 

class base2 : public ibase { 
    public: 
     virtual void foo() { std::cout<<"base2::foo"<<std::endl; } 
     virtual void boo(); 
}; 

int main() 
{ 
    ibase *inst1 = new base1; 
    ibase *inst2 = new base2; 

    inst1->foo(); 
    inst1->boo(); 
    inst2->foo(); 
} 

但是,當我嘗試使用下一個編譯器選項編譯:

g++ dfg.cpp -ansi -pedantic -Wall 

本實施例中生產下一輸出(使用克++ 4.3.0):

/tmp/ccv6VUzm.o: In function `base2::base2()': 
dfg.cpp:(.text._ZN5base2C1Ev[base2::base2()]+0x16): undefined reference to `vtable for base2' 
collect2: ld returned 1 exit status 

有人可以解釋爲什麼在鏈接失敗? boo()方法不被調用。

+0

爲什麼你不想拋出異常?它是檢測它是否被調用的最安全的方法。另外,如果某些子類不需要它,則可能需要修改接口。 – 2011-03-18 12:15:06

+0

@Space_COwbOy我以爲如果有人試圖使用這種方法,我會得到一個編譯器錯誤(就像你沒有定義一個不應該使用的方法的模板專門化一樣) – 2011-03-18 12:20:00

+1

純虛函數的一般思想是**強制**派生類來實現這些功能。現在你寧願不? :-) – 2011-03-18 17:05:59

回答

4

創建base2的vtable - 您使用base2。 vtable引用boo() - 所以你需要定義它。

10.3/8:

在類 聲明的虛擬函數將被定義,聲明或純 (10.4)在該類,或兩者;但不需要 診斷(3.2)。

1

它失敗了,因爲內部虛擬表需要一個指向的位置。它是否被調用並不重要,該vtable仍然被創建。

爲該方法創建一個空體並且您應該很好走。

1

必須實施base2中的方法,沒有辦法繞過它。多態性是一種運行時行爲,連接器無法知道boo將永遠不會被調用。您可以簡單地在基類中提供虛擬實現,而不是在派生類中實現該方法時不強制實現該虛擬實現。

0

你只是忘了實施virtual void base2::boo()。你必須實現它以實例化base2類。否則,您可以通過在base2類中聲明它來保持純虛擬。

3

單一定義規則規定每個函數used必須精確定義一次。術語used的定義包括下面的行:

用於一個虛擬函數,如果它是 不是純

這意味着,所有的非純虛函數必須定義,即使它們不叫

1

boo實際上可能不會被調用,但它被用來構建base2的v-表。

你必須定義什麼樣的行爲會發生,就是某人擁有一個base2並在其上調用boo()(通過它的基類指針),即使代碼中沒有實際調用它的位置。它是實施ibase合同的一部分。

設計當然是有缺陷的,如果你想要一個只允許foo的類,那麼應該有一個接口。

如果您的特定實例是呼叫是無操作,那麼這是該類的行爲。