dynamic_cast like type_id

Hello Everyone,
I'm trying to find a way to do a dynamic cast to the most derived object given a base class pointer or object. I've looked through the forums and tutorials, but can't find anything. Is this even possible without a long case or if-then block checking the type_id?

I would like to have a function which can take a base class as argument so all derived classes may be used as an argument, but I need to know the most derived type to properly process the argument in the function.

Thanks,

Jivan
What you want to do is most likely better done via the polymorphic mechanism already available. Why isn't what you want to do in the function in question implemented as a virtual member function?
The object I want to pass is a parameter to the entry point of a new thread, and the thread will use the object. The caller has a pointer to the parameter.

The new threads need their own copy of the parameter being passed, as there may be more than one thread spawned with the same parameter and the calling thread will delete the original parameter after spawning the threads.

In these circumstances, I don't know how to make a copy of the object while still dynamically retaining its type instead of casting it to the base class.

If I can't do this, I can add a reference counting mechanism to the objects, but since they are small and not terribly numerous it seems cleaner to make copies and let the threads clean up after themselves.

Any thoughts?
In these circumstances, I don't know how to make a copy of the object while still dynamically retaining its type instead of casting it to the base class.

I'm not sure if I get it right, but if I am, you can write a clone()-function for the objects you want to copy. If you still require functionality outside the class dependent on the derived type, you can use the overload resolution mechanism instead of RTTI switch/if structures.
Thanks for the feedback. Both of those would work, but writing a function for each derived class either as a function that takes it as a parameter, or as a method in the class that does exactly the same thing with only the type changed doesn't sit right with me. It would be an added bit of overhead to add new objects to this hierarchy that really shouldn't be there.

If these are my only options, I think I will go with a reference-counting scheme and use the polymorphic nature of pointers in C++.

Thanks again,

Jivan
You want the clone pattern as exception suggested. This is a common technique to solve the problem where some generic code is given a variable of some type and needs to copy it. Only the object knows how to copy itself.

1
2
3
4
5
6
7
8
9
10
11
class clonable {
  public:
     virtual clonable* clone() const = 0;
};

class derived: public clonable {
  public:
     // Requires CopyConstructible
     virtual derived* clone() const
        { return new derived( *this ); }
};


If I get it right (perhaps I don't, and perhaps I should stop posting when I'm not sure), Jivan wants to do something "nasty" with the object depending on the concrete layout (
The object I want to pass is a parameter to the entry point of a new thread
). Then a clone()-function may not suffice, since that could be memory-layout dependent.
You can, however, still use the overload mechanism - in combination with templates you *don't* have to write n functions for n derived types:
1
2
3
4
5
6
template<typename thread_type> void kickoff(thread_type* thread)
{
  thread_type* tmp = thread->clone();
  // switch stack pointer to tmp+4 and swap non-volatile registers etc.
  // or do whatever else it is you want to do
}

The compiler will generate the n functions (note that template functions can't be specialized partly. Instead, each "partly" specialized template function is a completely new template function which will participate in overload resolution. This behaves differently than the automatic template argument deduction for partly specialized templates!)
Hi exception, jsmith,
I think that the clone() pattern would work, but as I mentioned before, I'd like to avoid the overhead of adding a method to the derived objects.

You're not exactly right exception...I'm not going to do anything "nasty," but I think a function template is exactly what I'm looking for. I've never really looked at these before, thanks for the tip.
If I understand you correctly, the problem you are trying to solve is that you have a base class function that needs to know the most derived type of the object so you can copy it. The clone pattern is effectively the only solution. The bad news is you have little choice but to write the method. The good news is that the method is trivial to write.

Templates I don't think will work here because template and virtual don't mix -- you can't write a virtual template function.

Having said all that, boost may have solved this problem using complex template metaprogramming techniques; I'm not sure. If you want, you can research at www.boost.org, however my general impression is that even if they did solve the problem, it will be less time consuming for you to write the clone method for a bunch of objects than to try to integrate the metaprogramming solution.

And having said all that, you could fall back on a "ritualistic" solution by using CRTP (curiously recurring template pattern). The solution would work like this:

1
2
3
4
5
6
7
8
9
10
template< typename T >
class clonable {
   public:
      virtual T* clone() const
         { return new T( dynamic_cast< const T&>( *this ) ); }
};

class derived : public clonable<derived> {
   // ...
};


The limitations of this approach are:

1) If D is a class derived from clonable, then you cannot write a class D2 which is
derived from D and clonable.
2) The clone() method does not handle exceptions.
3) I'm not sure that this handles volatile either.
If I understand it right, what you want to do is a generic method at the server end to accept any type of object of a single type family (ie, derived from same base) and inside the code check and create an actual type of object that is passed-in.
Hence the function receives a base class type pointer which in fact may be a pointer to its derived object.
As the actually pointed-to object could be any of the base class family, hmmm, I guess you have to give an if-else condition structure to check and create relevant object for further processing.
If you dont want to mess-up the existing code, that is, writing an additional method for each class, then you better stay with the if-else with dynamic_cast
As it "is" to check for "if" or "else", then nothing wrong using if-else condition.
It would as simply as below:

void myServer(Base *pObject)
{
if (dynamic_cast<Derived1 *>(pObject)) { // if not null, it is Derived1 type
Derived1 d1;
// ada ada ada
...
}
else if (dynamic_cast<Derived2 *>(pObject) { // it is Derived2 type
{
Derived2 d2;
// ada ada ada
...
}
else {
// invalid thread or object
}


And I would not mix it with templates. It is bit different from what we are talking about. As it meant, a template is of a chunk of code for a generic type, which may not be of same family, while dynamic_cast<> works with/guarantees the objects passed-in are of a single family, that is they are compatible to the base class/type pointer parameter declared in.


Check it out. Good luck :)
Hi satm2008,
I really can't do the if/else solution, as my aim is to make code that can have new derived classes added without having to update it.

In case it sheds any light on my aim, I was writing an event handling package. I wanted to be able to add new events specific to different applications without changing the core event handling code.

I quickly found that function templates wouldn't cut it, as they need the object type at compile time.

I could have gone ahead with the "clone()" suggestion, but as it stands, the only thing I need to do to make a new event is to derive from the base. If the event needs some specific data, it can be added easily, but usually isn't needed. To also have to implement a clone() method for each derived class, even though a trivial method, would be burdensome. jsmith's template class could have worked well, but I'd already solved the problem before seeing it...I'm sure it will be useful sometime in the future though.

In the end I went ahead with a reference-counting container. I didn't really need a copy, it was just one way to make sure that the object existed while any of the threads that used it were still interested in it, and I thought (incorrectly ; ) that since the objects were so small copying them would be the simplest route to take.

Thanks to everyone who took the time to add their useful input : )
Last edited on
I think a class selector could be used to determine the type of the object and then a single dynamic_cast could be performed based on that...

EDIT: Actually, that's a little off. The selectors can identify the type passed to a template... If you're dealing with a template class.

Regardless, you could store the type information as an enum in your base class and then call a method to get the type. You could then have a switch that only attempts the cast once. This would avoid adding a vtable solely for type information.

Here's an example:

Types.H
1
2
3
4
5
6
7
8
9
10
#ifndef TYPES_H
#define TYPES_H
// list of type equates 
enum
{
    UNDEFINED = 0,
    ClassA,
    ClassB
};
#endif 


Base.H
1
2
3
4
5
6
7
8
9
10
11
#ifndef BASE_H
#define BASE_H
#include "Types.H"

class Base
{
    unsigned int _type;
public:
    Base( unsigned int type = UNDEFINED ) : _type( type ) {}
};
#endif 


A.H
1
2
3
4
5
6
7
8
9
#ifndef A_H
#define A_H
#include "Base.H"

struct A : public Base
{
    A() : Base( ClassA ) {}
};
#endif 


B.H
1
2
3
4
5
6
7
8
9
#ifndef B_H
#define B_H
#include "Base.H"

struct B : public Base
{
    B() : Base( ClassB ) {}
};
#endif 


Test.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "A.H"
#include "B.H"

int main( int argc, char * argv[] )
{
    Base * p = new A;

    switch( p->_type )
    {
        case A:
        {
            A * a = dynamic_cast<A *>( p );
            // ...
            delete a;
            break;
        }
    }

    return 0;
};


Note that the example has just been typed in here without any attempt to compile or test it...
Last edited on
seymore15074,
I don't think you read the discussion clearly. Using this approach you will still need to know all of the derived classes beforehand to populate the switch statement. The code is to handle all derived classes, even those that haven't been declared yet.
Topic archived. No new replies allowed.