1

Hi I've started working on some pre-existing code which consists of a tree of elements, each element is a descendant of a generic element which has a type data member.

The search functionality returns a generic element, the user then checks the type and can downcast to the specific type to access its specific information.

This code is for a mobile handset so using lots of dynamic_casts might be inefficient.

The code is new and not set in stone and so can be improved (I didn't write it, I've just joined the company and am working on it so don't want to rip it apart completely).

What are some options for a good design/use pattern going forward? (Its c++ but using type-checking and raw c casting (to avoid overheads of dynamic_casts) seems a bit old fashioned).

Is there any advantage in adding CastToXXX() type functions in the base class for example?

The types of derived classes will most likely be fixed.

Fructose
  • 145
  • 5

3 Answers3

2

dynamic_cast is not that slow, and you're likely not going to be able to do better. Profile and prove that it is a performance bottleneck before looking at alternative solutions. Never ever do anything because you maybe heard somewhere that it might be slow.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • dynamic_cast requires RTTI be enabled, likely for the entire module. Not only does this add additional overhead for objects where this type of casting is not required, it'll be redundant for the class(s) the OP mentioned, as they already embed type information. – Bukes Mar 21 '11 at 18:48
1

If dynamic_cast/RTTI is not an option, an easy way of dealing with this type of situation is by use of the Visitor Pattern

Basically, you define a base class that defines methods that do the casting for you safely:

    // Forward declarations.
class CFoo;
class CBar;

class CommonBase
{
public:
    virtual CFoo* GetFoo( void ) { return NULL };
    virtual CBar* GetBar( void ) { return NULL };
};

class CFoo : public GenericBase, public CommonBase
{
    .
    .
public:
    CFoo* GetFoo( void ) { return this };
};

class CBar : public GenericBase, public CommonBase
{
    .
    .
public:
    CBar * GetBar( void ) { return this };
};

Now, given a pointer to a CommonBase object one can downcast by "visting":

CommonBase *p;
CFoo pFoo = p->GetFoo();
if( pFoo )
{
    // Winner!
}
Bukes
  • 3,668
  • 1
  • 18
  • 20
  • I can understand that if you do (in C#): `CFoo p = ...; p.GetFoo()` that you'd get a CFoo object, but then it's useless since you already have one. but how does the language know that when you do: `CommonBase p = ...; p.GetFoo()` the base method shouldn't be called but the one in `CFoo` should? – ekkis Sep 07 '11 at 00:08
1

Let the base class in the tree structure have a pure virtual Visit() method.

class CBase {
  virtual void Visit(CVisitor* visitor) const = 0;
};

Let the inherited classes implement it:

class CFoo : public CBase {
  virtual void Visit(CVisitor* visitor) const {
    visitor->Accept(this);
  }
};

class CBar : public CBase {
  virtual void Visit(CVisitor* visitor) const {
    visitor->Accept(this);
  }
};

The final magic:

class CVisitor {
  void Accept(CFoo* foo) {
    // operate on CFoo*
  }
  void Accept(CBar* bar) {
    // operate on CBar*
  }
};

So all you need to do is to create Accept and Visit methods for new types and traverse the tree with the CVisitor class and then you can operate on any type in the tree without any pointer casts.

Hope this helps.

Cheers

rtn
  • 127,556
  • 20
  • 111
  • 121
  • in Bukes' reply below the disambiguation as to which type of object you want is accomplished by the fact that the method you call is defined in one class and not the other... how does it work with your scheme? can you show what a call would look like? – ekkis Sep 02 '11 at 20:06