我几天前问了一些clarifications on inheritance这个我仍在努力理解的概念。这是后续问题,因为我仍然面临问题。
在我的项目中,我有两种类型的对象,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;
由Hand或Head对象组成。在上一个问题中,我被告知这种方法是有道理的,我只需要使用boost static_pointer_cast
现在问题是,对于向量中的某些对象,我不知道它们是Hand
还是Head
,所以在我的代码中的某些时候我可以在{ {1}}一些cBodyParts
元素,一些Hand
元素以及一些Head
元素。经过一些进一步的分析后,我能够正确地将后者归类为BodyPart
或Hand
,并相应地修改向量中的元素,但我不知道如何制作它。我应该删除case类元素并创建一个具有相同属性的派生元素吗?如果是这样的话,我应该避免继承吗?
提前感谢您的帮助
答案 0 :(得分:4)
转换角色通常是设计糟糕的标志。演员有他们的位置,但这看起来不是。
您需要问自己,您想对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
找不到更新。
答案 1 :(得分:2)
髋骨与大腿骨相连......
我认为你有一些所有身体部位的复合物,也许是Body
类。
你想让身体做什么?
列表可能会继续下去。如果您确切知道Body
要做什么,可以将该函数放在BodyPart
基类中,并让Body
遍历所有连接的正文部分的复合层次结构,例如,调用render
。
另一种方法是使用Visitor
,这实际上是一种动态添加方法到静态继承层次结构的方法。
答案 2 :(得分:0)
正如Kerrek SB指出这根本不可行,但为了回答实际问题,dynamic_cast
正是你要找的。 p>
答案 3 :(得分:0)
使用虚拟功能,它们可以简化您的问题。
否则,您可以添加一些方法来区分不同类型。但是,只有在你不能以另一种方式进行时才会这样做,即如果你不能通过虚函数来做它。
示例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; }