3

I have a design problem that I am not sure how to handle in the best way. I want my code to be future proof and still not be to messy and complex (the plight of a geek).

Currently my design has the following setup

derived class D          derived class E
  ^                          ^
  |                          |
derived abstract class B  ->              derived class C
  ^                                            ^ 
  |                                            |
              Abstract Base class A

class B differs from class A, class D and class E differs from class B and C differs from class A.

As these classes differ I need to use the dynamic_cast operator.

A* a1 = new class C;
C* c1 = dynamics_cast<C*>(a1);
if(c1){ //Success!!!}
...

As you can see I will be wanting to use dynamic_cast a lot! I need to try and find a nice way of doing this that is not full of if() statements extra.

Is there a neat way of doing this? I seem to remember seeing something in a Scott Meyers book, but I am away from home and can not access it for a week or two.

Any references/examples would be much appreciated.

Also if need be I could make class B into an interface which would be a sort of solution

B* d1 = new D;
B* e1 = new E;

but not ideal.

NOTE: I have added this example to show my current design failure

class A {...};

class B: public A {
   public:
      virtual std::vector<objectType1*>& getObjectType1();
};

class C: public B {
   private:
     void newFunction();
};

A* c1 = new C();
std::vector<objectType1*> example = c1->getObjectType1(); // Wrong; need dyanmic_cast :-(

can not access getObjectType1() without dynamic_cast as the static type A does not know about this function. I need to rethink my design. Any ideas?

Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
MWright
  • 1,681
  • 3
  • 19
  • 31
  • You seem to be using differ to mean inherit, and you've given us no specifics as to why you need to downcast - you just seem to assuming you'll need to. Why? – Grimm The Opiner May 11 '12 at 10:16
  • 1
    There wouldn't be any point having classes if they didn't "differ" in some way, but what significant way do you mean? If you mean that they different in providing additional unrelated functionality and you don't want a fat interface, then that's unusual and ugly but valid, and `dynamic_cast<>` may be reasonable. A more concise and better scoped notation is `if (C* p = dynamic_cast(a1)) ...`. Still, "class B [being] an interface...would be a sort of solution" makes zero sense to me - you should explain what kind of functions you're putting in each class as you're probably doing it wrong. – Tony Delroy May 11 '12 at 10:37
  • 2
    Do not overuse `dynamic_cast`. Usage of dynamic cast is usually a sign of bad design, because it requires you to manually check the result (may be forgotten) and requires a conditional branch (relatively slow). Also if you add something to your class hierarchy, this means changes to all parts of the system where the `dynamic_cast`s are used. Instead use virtual methods, they do not require manual checking, uses an indirect branch (faster) and do not require manual tweaking. If you tell more of what you are trying to achieve, someone might be able to help you find a better design. – LiKao May 11 '12 at 10:37
  • Updated question from Note downwards – MWright May 11 '12 at 11:30
  • @MWright: actually, "Note downwards" just tells us what we already knew about the design (that you wanted to do extra stuff in the derived objects), and adds another code-smell: your classes are giving read-write access to their internal data - that means they can't possibly maintain any control of (invariants for) that data. What we need to know is what's the reason these objects are in the same hierarchy at all? What _are_ they? What are these additional operations? – Tony Delroy May 12 '12 at 06:39

1 Answers1

12

In a properly designed object hierarchy, the use of dynamic_cast is a fair rarity. Sure, it exists to cast up & down a polymorphic tree, but that doesn't mean you have to use it.

Think about this. Why would you need to use dynamic_cast, generally speaking? Because the base pointer you have doesn't provide the facilities you need, right? And what is the point of polymorphism? To provide different behavior for similar operations, where the behavior is chosen at run-time, right?

Aren't those two statements somewhat contradictory? If your object's interface is designed correctly, then you don't really care what kind of behavior is going to be employed when you call ->Foo() -- you just want to call ->Foo().

If you need to make frequent use of dynamic_cast, it's a code smell that tells you that there's something wrong with your interfaces. Maybe you're trying to shove too much in to one interface?

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 1
    This is exactly what I have done! A rethink is definitely needed I will edit my question. to show my exact design vault. – MWright May 11 '12 at 11:19