Search code examples
c++castingderived-class

Does having to "ask which exact type an object has" always indicate bad design?


At several places here in SO, it is claimed that having to know the exact type of an object and make a decision based on that (in an if-then-else manner) points to a design flaw, e.g. here.

I am wondering if this is always the case. In a current small educational project (which I'm using to learn C++) I want to implement arithmetic structures, i.e. terms (such as (3+4)*x-5) and equations (x=3*y+z). Now, from a structural point of view, equations are very similar to terms (particularly they can all be parsed using the Shaunting-yard algorithm), so I created a base class math_struct that both equation and term derive from:

class math_struct;
class term : public math_struct {...};
class equation : public math_struct {
    void resolve_to(std::string subTerm);
    ...
};

equation has a method resolve_to that term does not have (since an equation can be resolved to a variable, which a term cannot), but other than that they are equal.

Now I have a method to parse a math_struct from a string:

static std::unique_ptr<math_struct> parse_math_struct(std::string formula);

The resulting math_struct can either be a term or an equation, depending on what the input string looks like. To know which it is, I have to do a typeid check and perform a cast to use, if available, the resolve_to member function.

Is this a design flaw – and how could I improve it?


Solution

  • I don't know if I would call it a "flaw", but I would say the design could be improved. One potential problem with checking the type to see if you can call resolve_to is that the check could break if, for some reason, you find the need for a third class derived from math_struct. (Someone with a mathematical background should be aware that being unable to think of a reason why does not mean there is no reason why.)

    A more robust option is to add a virtual function to the base class, a simple Boolean that returns true iff you can call resolve_to.

    An even better option might be to think about what do you do if the thing you're dealing with is not an equation.

    To know which it is, I have to do a typeid check and perform a cast to use, if available, the resolve_to member function.

    What do you do if the resolve_to member function is not available? Why not have a virtual function on the base class that is overridden to do that thing for terms and overridden to call resolve_to for equations? (Or that is resolve_to for equations.)

    There might be a situation where the best option is to "ask which exact type an object has", but I do not believe this is it. (I know there's an XML parser that relies on this technique; I have not analyzed that to see if it could be improved.)