tags:

views:

119

answers:

4

This question seems like it might be somewhat common, but I didn't find anything when scowering StackOverflow or the interwebs.

I came across a method in a C++ class that takes a list of (for example) Parent objects. For this example, assume that there are two classes that derive from Parent: Child1 and Child2.

For each object in the list, the method checks if the object is of type Child2 (via a IsOfType() method that each class implements), and if so, it calls a method that is only provided by the Child2 class.

Is this an issue in that the list-processing method cannot treat each object the same? I've seen this done in other places as well, so it seems it might be a common practice to some degree.

One option might be to declare the Child2 method in the Parent class so that all Parent objects implement it. However, in this case, only the Child2 class would actually implement any behavior when overriding the method.

Your thoughts? Thanks in advance!

+1  A: 

If your IsOfType() test passes, you can cast the (pointer to the) parent object to a Child2 object and access its specific member functions.

EDIT: This depends on your design and on how strict you ensure the IsOfType() implementation will give correct answers (i.e. it also works when you add new subclasses in a week). It might be safer to make use of the builtin Typeid instead. Implementing every possible method any child would ever have in the parent would be difficult, so upcasting is ok when the method is really semantically specific to the Child2 class.

catchmeifyoutry
The list-processing method currently behaves like you described, only it does not use Typeid. Maybe the method can stay as-is for the time being, but possibly use Typeid instead of the IsOfType() method. Thanks for this suggestion!
bporter
+3  A: 

I think the following is a better solution for this problem.

class Parent {
public:
   virtual int doSomething() {}
};

class Child1 : public Parent {
};

class Child2 : public Parent {
public:
    virtual int doSomething();

Now you just omit the IsOfType call altogether and call doSomething on all of the pointers passed to you.

The only good reason I can think of as to why you'd have an IsOfType function is if you don't have control over the Parent class and can't modify it to add the doSomething method.

Glen
It is bad if doSomething has arguments and only Child2 knows type of these arguments
Alexey Malistov
@Alexey, if that's the case then I think it's a bad design and it's not a problem that's really suited for polymorphism.
Glen
Alternatively, if it feels wrong to have doSomething() in the Parent interface, then maybe you rather keep Child1 and Child2 instances in two separate lists. Maybe Child1 and Child2 do not have enough in common to warrant mixing them in one list.
digitalarbeiter
@digitalarbeiter, yes, that would work. though in that case I probably wouldn't have them both interit from the Parent as they're really not similar enough.
Glen
+2  A: 

You could declare the new method in an interface that only Child2 implements. You could then use dynamic_cast<ISomeOtherInterface> to see if the object supports the extended feature. This cast will result in a null pointer for objects that don't support the additional interface.

This would allow you to create other objects that implement this feature, without requiring your list processing to know about each specific object type.

jheddings
This might be a really good approach. Thanks for the suggestion!
bporter
A: 

You might find the Visitor Pattern useful in this instance. This will allow the objects themselves (child1, child2 etc) to call you back with their static type and take appropriate action.

Phil Nash