[英]Converting objects of base class to derived class
幾天前,我問過一些關於繼承的問題 ,我仍然想理解這個概念。 這是后續問題,因為我仍然面臨問題。
在我的項目中,我有兩種類型的對象,即Hand和Face,均從基類BodyPart繼承。 BodyPart是這樣的:
class BodyPart
{
public:
typedef boost::shared_ptr<BodyPart> BodyPartPtr;
BodyPart();
virtual ~BodyPart();
private:
int commonMember1;
double commonMember2;
public:
int commonMethod1();
int CommonMethod2();
}
而Hand是這樣的:
class Hand : public BodyPart
{
public:
Hand();
~Hand();
private:
int numFingers;
double otherVar;
public:
int getNumFingers();
void printInfo();
}
我也有一個BodyPart元素向量
std::vector<BodyPart::BodyPartPtr> cBodyParts;
由手或頭對象組成。 在上一個問題中,我被告知這種方法是有意義的,我只需要使用boost static_pointer_cast
從基類轉換為派生類即可。
現在,問題是對於向量中的某些對象,我不知道它們是Hand
還是Head
,所以在我的代碼中的某些時候,我可以在cBodyParts
中cBodyParts
一些Hand
元素,一些Head
元素以及一些BodyPart
元素。 經過進一步分析,我能夠將后者正確分類為“ Hand
或“ Head
並相應地修改矢量中的元素,但是我不知道如何制作。 我是否只刪除case類元素並創建具有相同屬性的派生類? 如果這樣的話,我應該避免繼承嗎?
在此先感謝您的幫助
編輯:我擴大了示例,使它們更清晰。
強制轉播通常是不良設計的標志。 演員有他們的位置,但事實並非如此。
您需要問自己要使用cBodyParts
存儲的對象做什么。 當然,您將用Hand
或Head
來做不同的事情,但是您可能可以以某種方式抽象它們:這就是虛函數的作用。 因此,除了已經為類編寫的內容之外,您還需要在其中添加一個附加的虛函數:
class BodyPart
{
// Same as you wrote, plus:
public:
virtual void InitialisePart() = 0; // Pure virtual: each body part must say how to process itself
virtual void CalibrateJoints() {} // Override it only if the body part includes joints
}
class Head : public BodyPart
{
// Same as you wrote, plus:
public:
virtual void InitialisePart() {
// Code to initialise a Head
}
// Since a Head has no joints, we don't override the CalibrateJoints() method
}
class Hand : public BodyPart
{
// Same as you wrote, plus:
public:
virtual void InitialisePart() {
// Code to initialise a Hand
}
virtual void CalibrateJoints() {
// Code to calibrate the knuckles in the hand
}
}
然后,您不再需要任何強制轉換。 例如:
for (BodyPart::BodyPartPtr part : cBodyParts) {
part->InitialisePart();
part->CalibrateJoints(); // This will do nothing for Heads
}
如您所見,完全沒有強制轉換,一切都會正常進行。 該方案是可擴展的。 如果您以后決定需要從BodyPart
繼承的其他類,只需編寫它們,您的舊代碼即可正常工作:
class Torso : public BodyPart
{
public:
virtual void InitialisePart() {
// Code to initialise a Torso
}
// The Torso has no joints, so no override here for CalibrateJoints()
// Add everything else the class needs
}
class Leg : public BodyPart
{
public:
virtual void InitialisePart() {
// Code to initialise a Leg
}
virtual void CalibrateJoints() {
// Code to calibrate the knee
}
// Add everything else the class needs
}
現在,您無需更改您先前編寫的代碼:上面的for
循環可以正確運行,並且找到的Torso
或Leg
不需要更新。
髖骨連接到大腿骨...
我認為您的身體各個部分都有一些組合,也許是Body
類。
你想要身體做什么?
該清單可能會繼續下去。 如果確切知道您要Body
做什么,則可以將該函數放在BodyPart
基類中,並使Body
遍歷所有連接的身體部件的復合層次結構,例如,調用render
。
一種替代方法是使用Visitor
,這實際上是一種將方法動態添加到靜態繼承層次結構的方法。
正如Kerrek SB指出的那樣,這根本不可行,但是為了回答實際問題,您正在尋找dynamic_cast
。
使用虛函數,它們將簡化很多問題。
否則,您可以添加一些方法來區分不同的類型。 但是, 僅當您不能以其他方式執行此操作時 ,即無法通過虛函數執行操作時,才執行此操作。
范例1:
// in BodyPart; to be reimplemented in derived classes
virtual bool isHand() const { return false; }
virtual bool isHead() const { return false; }
// in Hand (similar to what will be in Head)
bool isHand() const { return true; }
// How to use:
BodyPart::pointer ptr = humanBodyVector[42]; // one item from the array
if(ptr->isHand())
processHand(/*cast to hand*/)
else if(ptr->isHead())
// ...
示例2:讓派生類處理演員表
// in BodyPart; to be reimplemented in derived classes
virtual Hand* toHand() const { return 0; }
virtual Head* toHead() const { return 0; }
// in Hand (similar to what will be in Head)
Hand* toHand() const { return this; }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.