cannot dynamic_cast 't' (of type 'void*') to type 'struct mom::object*' (source is not a pointer to

V

verec

I just do not understand this error.
Am I misusing dynamic_cast ?

What I want to do is to have a single template construct
(with no optional argument) so that it works for whatever
T I want to use it with. Now, if that T happens to be some
subclass of a known base class (object, in this case), I
want to perform some extra stuff ...

I've read Faq#35, and the most natural solution would have
been to write the function as a non static envelope member
parameterized on T, but the reason the code is "out-line" is
because of a circular dependency that would be introduced
between object & envelope if I was to let envelope.hpp know
about the innards of object.hpp.

I solved this by using a "free standing", non templatized regular
function, whose definition, inside envelope.cpp is now allowed
to include object.hpp ...

/Users/verec/Tools/trunk/Style/tests/build/mom/../../../src/common/mom/envelope.cpp:68:
error:

cannot dynamic_cast 't' (of type 'void*') to type
'struct mom::eek:bject*' (source is not a pointer to class)

file envelope.hpp

namespace mom {
// ...
void construct(void * t) ; // <-- decl

template <typename T> struct envelope {


// ...

static void * cast(T * t) {

return dynamic_cast<void *>(t) ;

}

// ...

envelope(T * q = 0) : body(q) {
// ...
construct(cast(body)) ;

}
} ;
}

file envelope.cpp

#include "mom/envelope.hpp"
#include "mom/object.hpp"

namespace mom {

// ...
void
construct(void * t) {
object * o = dynamic_cast<object *>(t) ; // <-- defn: where
GCC 4.0 chokes.
if (o) {
o->construct() ;
}
}
}

for completeness ...
file opbject.hpp

namespace mom {
struct object {
object() {}

virtual
~object() {}

virtual void
construct() {}
// ...
} ;
}

Any idea what I'm doing wrong?

Many thanks
 
A

Alipha

verec said:
I just do not understand this error.
Am I misusing dynamic_cast ?

yes. you can't cast from void* because the compiler can't know what
type the object really is. you can only cast from polymorphic types (in
which case, the compiler typically looks at the v-table pointer to
determine what type the object really is).

What I want to do is to have a single template construct
(with no optional argument) so that it works for whatever
T I want to use it with. Now, if that T happens to be some
subclass of a known base class (object, in this case), I
want to perform some extra stuff ...

I've read Faq#35, and the most natural solution would have
been to write the function as a non static envelope member
parameterized on T, but the reason the code is "out-line" is
because of a circular dependency that would be introduced
between object & envelope if I was to let envelope.hpp know
about the innards of object.hpp.

I solved this by using a "free standing", non templatized regular
function, whose definition, inside envelope.cpp is now allowed
to include object.hpp ...

/Users/verec/Tools/trunk/Style/tests/build/mom/../../../src/common/mom/envelope.cpp:68:
error:

cannot dynamic_cast 't' (of type 'void*') to type
'struct mom::eek:bject*' (source is not a pointer to class)

file envelope.hpp

namespace mom {
// ...
void construct(void * t) ; // <-- decl

void construct(void * t);
void construct(object * t);

problem solved?
template <typename T> struct envelope {


// ...

static void * cast(T * t) {

return dynamic_cast<void *>(t) ;

the cast is completely unnecessary, T* converts to void* implicitly,
where T is not a function or member function type. of course, if you
convert to void*, you lose all type info, which probably isn't a good
thing.

you might want to consider boost::any, however that probably won't help
with your overall design. www.boost.org
}

// ...

envelope(T * q = 0) : body(q) {
// ...
construct(cast(body)) ;

}
} ;
}

file envelope.cpp

#include "mom/envelope.hpp"
#include "mom/object.hpp"

namespace mom {

// ...
void
construct(void * t) {
object * o = dynamic_cast<object *>(t) ; // <-- defn: where
GCC 4.0 chokes.
if (o) {
o->construct() ;
}
}
}

for completeness ...
file opbject.hpp

namespace mom {
struct object {
object() {}

virtual
~object() {}

virtual void
construct() {}
// ...
} ;
}

Any idea what I'm doing wrong?

quite frankly, any program design which includes such an incredibly
generic object base class usually smells of a bad design. you can't do
anything with this object other than construct or destroy it. you'd
have to cast to a more specific derived class type to do anything
useful with it, which trying to figure out what derived class to cast
to is generally a "fun" exercise. C++ doesn't have an object base class
for a reason.
 
A

Alf P. Steinbach

* Alipha:
the cast is completely unnecessary, T* converts to void* implicitly,
where T is not a function or member function type.

Given the rest of the code one might think so, but this is a very special
case: a dynamic cast to void* gives a pointer to the most derived object.
E.g., T could here be an interface that t, an object instantiated from C,
implements. The dynamic cast gives a pointer to the C object. The problem
is doing something useful with that void* pointer. There is no dynamic cast
back again, so except for comparing pointer values (which is the only
portable usage I know of) the client code needs to know the type C.
 
V

verec

yes. you can't cast from void* because the compiler can't know what
type the object really is. you can only cast from polymorphic types (in
which case, the compiler typically looks at the v-table pointer to
determine what type the object really is).

Thanks. So the cast to void * is one way street, even though *I am*
telling the compiler what I expect it to cast to: why is dynamic_cast
supposed to return 0 or even throw bad_cast if not for the possibility
I may have lied to the compiler... Well, I'l learn to live with that
I suppose...

Given the rest of the code one might think so, but this is a very special
case: a dynamic cast to void* gives a pointer to the most derived object.
E.g., T could here be an interface that t, an object instantiated from C,
implements. The dynamic cast gives a pointer to the C object. The problem
is doing something useful with that void* pointer.

Store them in a map, no matter what branch of the derivation was used.
There is no dynamic cast back again

This was the most unexpected event for today :-( I'll have to rethink
how I'm going to cope with that.

Many thanks to both.
 
B

benben

Thanks. So the cast to void * is one way street, even though *I am*
telling the compiler what I expect it to cast to: why is dynamic_cast
supposed to return 0 or even throw bad_cast if not for the possibility
I may have lied to the compiler... Well, I'l learn to live with that
I suppose...

If you are so confident you can use reinterpret_cast. I wouldn't...

Ben
 
V

verec

If you are so confident you can use reinterpret_cast. I wouldn't...

Many thanks for the idea. It turns out that I was just confused about
the need to:
- forward declare to avoid circular dependencies
- have every single template definition inside a header file so that
the compiler could instantiate it as and when.

The code now reads:

file envelope.hpp

namespace mom {
// ...
struct object ; // forward decl
void construct_if(object * o) ;

// ...
template <typename T> struct envelope {
// ...
envelope(T * q = 0) : body(q) {
// ...
construct_if(dynamic_cast<object *>(body)) ;

}
} ;
}

file envelope.cpp

#include "mom/envelope.hpp"
#include "mom/object.hpp"

namespace mom {

// ...
void
construct_if(object * o) {
if (o) {
o->construct() ;
}
}
}

And I'm happy :)

Many Thanks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,828
Latest member
LauraCastr

Latest Threads

Top