2011-08-23 35 views
3

實現抽象類成員是否有可能實現一個抽象基類,成員從在C++中另一個父類繼承?在父類

它工作在C#,所以我試圖做它在C++:雖然

// Virtual destructors omitted for brevity 

class ITalk 
{ 
public: 
    virtual void SayHi() = 0; 
}; 

class Parent 
{ 
public: 
    void SayHi(); 
}; 

class Child : public Parent, public ITalk 
{ 
}; 

void Parent::SayHi() 
{ 
    std::printf("Hi\n"); 
} 

我的編譯器真的不喜歡它:

ITalk* lChild = new Child(); // You idiot, Child is an abstract class! 
lChild->SayHi(); 

我不能添加public ITalkParent類,因爲「基礎類‘的iTalk’已經是一個基類的‘父’的。」我可以移動public ITalkParent類,但在我的特殊情況下,很多事情複雜化。

回答

4

沒有因爲你真的是沒有對方的任何知識兩個基類。

 
Italk Parent 
/\  /\ 
    |   | 
    +---------+ 
     | 
    Child 

如果Parent和Italk有兩個名爲i的變量,則會出現兩個「i」,ITalk :: i和Parent :: i的實例。要訪問他們,你不得不完全限定你想要哪一個。

同樣是方法正確,lChild有兩個方法稱爲sayHi的,你需要弄清楚你的意思是哪一個調用sayHi的時候,因爲多重繼承使得有曖昧。

你有家長的sayHi

lChild->Parent::SayHi(); 

和的iTalk的sayHi的:

lChild->ITalk::SayHi(); 

後者是純虛因爲它的抽象必須在本地子覆蓋。爲了滿足這一點,你需要定義

Child::SayHi(); 

現在就躲在父母:: sayHi的()調用sayHi的時候沒有它作用域到類:

lChild->SayHi() //parent's now hidden, invoke child's 

當然孩子:: sayHi的( )可以調用Parent :: SayHi():

void Child::SayHi() 
{ 
    Parent::SayHi(); 
} 

這將解決您的問題。

+0

這使得它更清晰如何編譯器看到這些函數。如果說編譯器只查看本地類,並且在查找「ITalk :: SayHi()'的重載實現時不會搜索繼承樹,是否正確? –

+0

是的,這是真的。當實例化一個對象時,編譯器會從你正在實例化的東西中查找並確保直接在它上面的任何仍然是純虛擬的東西已經在本地實例化**。 –

1

ITalk包含純虛函數SayHi(),所以如果您希望能夠實例化從ITalk派生的類,該類必須實現SayHi()

class Child : public Parent, public ITalk 
{ 
public: 
    void SayHi() { std::cout << "Hi!" << std::endl; } 
}; 

另外,Parent可以從ITalk(但不是Child)繼承,你已經發布的代碼將工作。

另外,當實現具有虛函數的基類時,必須爲定義這些基類的虛擬析構函數。所以的iTalk應該是:

class ITalk 
{ 
public: 
    virtual void SayHi() = 0; 
    virtual ~ITalk() {} 
}; 

如果你不這樣做,下面的產生不確定的行爲

ITalk* lChild = new Child(); 
lChild->SayHi(); 
delete lChild; 
+0

因此......不是? 'Child'類不能繼承它想用來實現'ITalk'的成員嗎? –

+0

@emddudley是的,不能這樣做。道格T.的[答案](http://stackoverflow.com/questions/7167558/implementing-abstract-class-members-in-a-parent-class/7167649#7167649)解釋了爲什麼 – Praetorian

0

嘗試使用虛擬繼承

class ITalk 
{ 
public: 
    virtual void SayHi() = 0; 
}; 

class Parent: virtual ITalk 
{ 
public: 
    void SayHi(); 
}; 

class Child : public Parent, public virtual ITalk 
{ 
}; 

void Parent::SayHi() 
{ 
    std::printf("Hi\n"); 
} 
1

這是不可能的,因爲你寫它來完成。其原因是,每個非靜態方法都需要對象(this)進行操作(這裏您不使用任何對象的字段或方法,但這並不重要),並且此對象必須適合類型。 Parent::sayHi預計this的類型爲Parent,並且由於ITalk根本與Parent無關,因此Parent::sayHiITalk::sayHi方法基本上是不兼容的。

C++有靜態類型系統,所以在編譯時必須知道類型。使用動態類型的語言通常對這樣的構造不那麼嚴格,因爲他們可以在函數調用時測試對象是否是合適的類。

在C++中實現這種行爲是簡單地讓Child::sayHi調用Parent::sayHi最簡單的方法,因爲孩子是「知道」只有一流的在哪裏ParentITalk,他們應該如何相關。

class Child : public Parent, public ITalk 
{ 
    virtual void sayHi(){ Parent::sayHi(); } 
};