4

I asked a couple days ago some clarifications on inheritance, a concept I am still trying to understand. Here is the follow up question, since I am still facing problems.

In my project I have 2 types of objects, Hand and Face, both inheriting from the base class BodyPart. BodyPart is something like this:

class BodyPart
{
  public:
  typedef boost::shared_ptr<BodyPart> BodyPartPtr;

  BodyPart();
  virtual ~BodyPart();

  private:
  int commonMember1;
  double commonMember2;

  public:
  int commonMethod1();
  int CommonMethod2();
}

while Hand is something like this:

class Hand : public BodyPart
{
  public:
  Hand();
  ~Hand();

  private:
  int numFingers;
  double otherVar;

  public:
  int getNumFingers();
  void printInfo();
}

I also have a vector of BodyPart elements

std::vector<BodyPart::BodyPartPtr> cBodyParts;

composed of Hand or Head objects. In the previous question I was told that this approach makes sense, I just had to cast from the base class to the derived using boost static_pointer_cast

Now, the problem now is that for some of the objects in the vector I don't know whether they are Hand or Head, so at some point in my code I can have in cBodyParts some Hand elements, some Head elements as well as some BodyPart elements. After some further analysis I am able to correctly classify the latter as either Hand or Head and modify accordingly the elements in the vector, but I have no idea on how to make it. Shall I just delete the case class element and create a derived one with the same property? Shall I just avoid inheritance in case like this?

Thanks in advance for the help

Community
  • 1
  • 1
  • 5
    Well, as you just discovered for yourself, casting does *not* really make sense. Use virtual member functions in the base class instead to expose the desired abstract functionality. – Kerrek SB Jan 09 '13 at 10:05

4 Answers4

4

EDIT: I have augmented the examples to make them clearer.

Relaying on casts is usually a sign of a bad design. Casts have their place, but this does not look to be it.

You need to ask yourself what do you want to do with the objects stored in cBodyParts. For sure, you will be doing different things with a Hand or with a Head, but you can probably abstract them somehow: this is what virtual functions do. So, in addition to what you have already written for your classes, you would just need an additional virtual function in them:

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
  }
}

And then you no longer need any casts. For instance:

for (BodyPart::BodyPartPtr part : cBodyParts) {
  part->InitialisePart();
  part->CalibrateJoints(); // This will do nothing for Heads
}

As you can see, no casts at all and everything will work fine. This scheme is extensible; if you later decide that you need additional classes inheriting from BodyPart, just write them and your old code will work correctly:

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
}

Now you don't need to change the code you wrote previously: the for loop above will work correctly with and Torso or Leg it finds with no need for an update.

Gorpik
  • 10,940
  • 4
  • 36
  • 56
  • Thanks Gorpik. This approach is definitely nice and elegant, but I don't see how does it deal with the necessity to convert objects from the base class to the derived ones, once I found out out what my vector elements actually are –  Jan 09 '13 at 10:50
  • 1
    @Stocastico You need to get rid of the necessity to convert from base to derived. – Peter Wood Jan 09 '13 at 10:57
  • @Stocastico The main attractive of this technique is that you **don't** actually need to convert to derived class at all. What do you want to convert for? – Gorpik Jan 09 '13 at 10:58
  • Well, because at the beginning of the processing there are cases where I do not know whether an object is Hand or Head, so I just store it in the vector as a BodyPart. Further analysis allows me to find out what the object is, and that's the moment when I have to make the conversion. I guess, as @Peter Wood says, I should get rid of this necessity –  Jan 09 '13 at 11:13
  • 1
    @Stocastico If you read again at what you just wrote, you will see that you have not answered my question. You don't need to convert just because you know that your `BodyPart` is really a `Hand`: you need to convert if there is something you must do and cannot without converting. Is there anything you need to do that cannot be accomplished with virtual functions? – Gorpik Jan 09 '13 at 11:21
  • Ok, now it's clear, sorry. Well, suppose I want to set the values of some member variables of the class `Hand`, and this variables only belong to the `Hand` class (for example, `int thumbLength`). How could I do that? Defining a pure virtual method in the base class would require to override it in every derived class... it doesn't seem like a good approach, doesn't it? –  Jan 09 '13 at 11:32
  • @Stocastico In fact, that is the right approach. Well, if it is something that will only be done in some classes, you can use a normal (non pure) virtual method. I will extend the examples in the answer so you can see this better. – Gorpik Jan 09 '13 at 11:34
  • 1
    @Stocastico If you want to modify individual parts of the body, create controllers for each part. So, iterate over each body part saying `makeControl`, and it will create a control appropriate to its attributes. Then use that to modify it. – Peter Wood Jan 09 '13 at 11:46
  • Ok Gorpik, thanks a lot. I am going to mark this as solved, since now I get the picture. One last question, though: suppose the vector `cBodyParts` is filled by pushing back a `Hand` object and then a `BodyPart` object. After that, I find out that the 2nd object is actually a `Hand`, and I want to set its `numFingers`. Is there a way to do that if I created that 2nd object using `new BodyPart()`, thus not allocating memory for the `numFinger` variable? –  Jan 09 '13 at 12:33
  • @Stocastico No. If you create it as just a generic `BodyPart`, it cannot be a `Hand`; there is some design fault somewhere. In fact, you should probably not be able to create a `BodyPart`, just as we humans don't have generic body parts; you should always create the real, concrete parts. – Gorpik Jan 09 '13 at 12:59
  • 1
    Ok. As I thought. Thanks :-) –  Jan 09 '13 at 13:04
2

The hip bone's connected to the thigh bone...

I take it you have some composite of all the body parts, maybe a Body class.

What do you want the body to do?

  • Render itself
  • Serialise
  • Ouput its volume, or bounding box, or some other metric
  • Re-orient itself in response to input
  • Respond to an inverse-kinematic physical model

The list could probably go on. If you know exactly what you want the Body to do you can put that function in the BodyPart base class, and have Body iterate over the composite hierarchical structure of all the connected body parts, calling render, for example.

An alternative is to use a Visitor, which is effectively a way of dynamically adding methods to a static inheritance hierarchy.

Peter Wood
  • 23,859
  • 5
  • 60
  • 99
0

As Kerrek SB pointed out this is not feasible at all, but for the sake of answering the actual question, dynamic_cast is what you are looking for.

filmor
  • 30,840
  • 6
  • 50
  • 48
0

Use virtual functions, they will simplify a lot your problem.

Else, you can add some methods to distinguish between different types. However, do it only if you cannot do it another way, ie if you cannot do it via virtual functions.

Example 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())
    // ...

Example 2: let the derived classes handle the cast

// 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; }
Synxis
  • 9,236
  • 2
  • 42
  • 64
  • 1
    although, this is a poor implementation, since `isHand` implies that the base class actually has knowledge of its derived classes. The virtual functions should only be related to the actual class, for instance, `dismember()` or `hasBloodFlow()` or `move()`, that is, stuff that is related to `BodyPart` – default Jan 09 '13 at 10:15
  • There are cases where the base class has knowledge of its derived classes, or at least some of its derived classes. The second technique can be seen in some parts of Qt, for example. – Synxis Jan 09 '13 at 10:19
  • This may make sense in case when the hierarchy is sure not to be extended. With a base class called `BodyPart`, I don't think we are in such case. – Gorpik Jan 09 '13 at 10:20
  • @Synxis Just because others do it, that doesn't mean it is correct :) – default Jan 09 '13 at 10:22
  • @GorPik Not fully agree. I agree with you for the point where the hierarchy is sure not to be extended. But for the other point : all parts of the body are known, and you cannot get an extra member ;) – Synxis Jan 09 '13 at 10:22
  • @Synxis: Can you enumerate all body parts and be sure that you are missing none? Besides, you should not write classes you don't need. If you don't need an `Elbow` class, don't write it now. But maybe in the future you will, extending the hierarchy. – Gorpik Jan 09 '13 at 10:35
  • Thanks Synxis. Just to be clear, though. Suppose ptr in your example one is a member of BodyPart, but I find out, by some other methods, that it should be a Hand object. How can I change ptr to be a Hand? shall I use dynamic cast as suggested in @filmor's answer? –  Jan 09 '13 at 10:39