dynamic_cast for down casting from base to concrete type

M

mijobee

Hello Everyone,

I just wanted to check that I'm using dynamic_cast correctly. I have a
hierarchy of objects using pure virtual classes and virtual inheritance
to implement interfaces. I ran into a problem using C-style casting to
an instance of a derived class from its interface type to a variable of
its concrete type. I was confused because I thought C-style casts
always compiled even if they wouldn't run correctly at runtime. I
modified the code to use dynamic_cast which seems correct, compiles and
runs but have found some contradictory information about its use so I
wanted to confirm I'm using it correctly. The code below illustrates
my problem. Thanks for your help.


#include <stdio.h>

class IObject
{
public:
virtual bool Equals(IObject *object) = 0;

};

class IList : public virtual IObject
{
public:
virtual IObject *Get(int index) = 0;
};

class Object : public virtual IObject
{
public:
virtual bool Equals(IObject *object) {
return this == object;
}
};

class ArrayList : public Object, public virtual IList
{
public:
virtual IObject *Get(int index) {
return this; // Just return something
}
};

class String : public Object { };
int main(int argc, char *argv[])
{
IList *list = new ArrayList();
IObject *obj = new String();
String *str = (String *)obj;
// This works: String *str = dynamic_cast<String *>(obj);
printf("str %s null.\n\0", str == 0 ? "is" : "is not");

}

Example.cpp: In function 'int main(int, char**)':
Example.cpp:39: error: cannot convert from base 'IObject' to derived
type 'String' via virtual base 'IObject'
 
D

Daniel T.

"mijobee said:
Hello Everyone,

I just wanted to check that I'm using dynamic_cast correctly. I have a
hierarchy of objects using pure virtual classes and virtual inheritance
to implement interfaces. I ran into a problem using C-style casting to
an instance of a derived class from its interface type to a variable of
its concrete type. I was confused because I thought C-style casts
always compiled even if they wouldn't run correctly at runtime. I
modified the code to use dynamic_cast which seems correct, compiles and
runs but have found some contradictory information about its use so I
wanted to confirm I'm using it correctly. The code below illustrates
my problem. Thanks for your help.


#include <stdio.h>
#include said:
class IObject
{
public: virtual ~IObject() { }
virtual bool Equals(IObject *object) = 0;

};

class IList : public virtual IObject
{
public:
virtual IObject *Get(int index) = 0;
};

class Object : public virtual IObject
{
public:
virtual bool Equals(IObject *object) {
return this == object;
}
};

class ArrayList : public Object, public virtual IList
{
public:
virtual IObject *Get(int index) {
return this; // Just return something
}
};

class String : public Object { };
int main(int argc, char *argv[])
{
IList *list = new ArrayList();
IObject *obj = new String();
String *str = (String *)obj;

The above doesn't work because Object derives from IObject virtually.
// This works: String *str = dynamic_cast<String *>(obj);
printf("str %s null.\n\0", str == 0 ? "is" : "is not");
delete list;
delete obj;
}

Example.cpp: In function 'int main(int, char**)':
Example.cpp:39: error: cannot convert from base 'IObject' to derived
type 'String' via virtual base 'IObject'

Frankly, this isn't Java. I would dump the Object class and keep things
by value when possible. But then I would use std::string instead of
inventing my own string class...
 
G

Gianni Mariani

Standard answer to dynamic cast ... If you have to use it, you're
almost certainly doing somthing wrong - that said, let's move on.
Hello Everyone,

I just wanted to check that I'm using dynamic_cast correctly. I have a
hierarchy of objects using pure virtual classes and virtual inheritance
to implement interfaces. I ran into a problem using C-style casting to
an instance of a derived class from its interface type to a variable of
its concrete type. I was confused because I thought C-style casts
always compiled even if they wouldn't run correctly at runtime. I
modified the code to use dynamic_cast which seems correct, compiles and
runs but have found some contradictory information about its use so I
wanted to confirm I'm using it correctly. The code below illustrates
my problem. Thanks for your help.


#include <stdio.h>

class IObject
{
public:
virtual bool Equals(IObject *object) = 0;

};

class IList : public virtual IObject
{
public:
virtual IObject *Get(int index) = 0;
};

class Object : public virtual IObject
{
public:
virtual bool Equals(IObject *object) {
return this == object;
}
};

class ArrayList : public Object, public virtual IList
{
public:
virtual IObject *Get(int index) {
return this; // Just return something
}
};

class String : public Object { };
int main(int argc, char *argv[])
{
IList *list = new ArrayList();
IObject *obj = new String();
String *str = (String *)obj;
// This works: String *str = dynamic_cast<String *>(obj);
printf("str %s null.\n\0", str == 0 ? "is" : "is not");

}

Example.cpp: In function 'int main(int, char**)':
Example.cpp:39: error: cannot convert from base 'IObject' to derived
type 'String' via virtual base 'IObject'

I don't in particular understand why the C style cast fails, but it is a
good thing IMHO because it's time to give up on it. It's too error
prone. If I were you I would look at the compiler docs to see if the
compiler has a flag to permit such things.


String *str = dynamic_cast<String *>(obj);

if ( str != 0 )
{
// obj IS a pointer to String
// go ahead an use str
} else {
// obj IS NOT at pointer to String
// so other thing
}
 
G

Greg

Gianni said:
Standard answer to dynamic cast ... If you have to use it, you're
almost certainly doing somthing wrong - that said, let's move on.

True, but with one notable exception that is relevant to the original
question.

A dynamic_cast should always be used when casting from a derived class
to a virtual base. Using a static_cast (which is always a safe
operation when casting from a derived class to a non-virtual base)
leads to undefined behavior when casting to a virtual base class.

Greg
 
C

Clark S. Cox III

Greg said:
True, but with one notable exception that is relevant to the original
question.

A dynamic_cast should always be used when casting from a derived class
to a virtual base. Using a static_cast (which is always a safe
operation when casting from a derived class to a non-virtual base)
leads to undefined behavior when casting to a virtual base class.

C and V please. If I understand you:

struct A {};
struct B : virtual A {}

int main()
{
B *b = new B;
/* You claim that this is undefined behavior? */
A * a = static_cast<A*>(b)
}

I haven't found anything that would suggest that.
 
G

Greg

Clark said:
C and V please. If I understand you:

struct A {};
struct B : virtual A {}

int main()
{
B *b = new B;
/* You claim that this is undefined behavior? */
A * a = static_cast<A*>(b)
}

I haven't found anything that would suggest that.

Actually, I had the direction of the cast reversed. The corrected
example would be::

struct A {};
struct B : virtual A {}

int main()
{
A *a = new B;

B * b = static_cast<B*>(a); // undefined
}

If A were an ordinary base class of B then the static_cast would be OK.

Greg
 

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

Forum statistics

Threads
473,961
Messages
2,570,130
Members
46,689
Latest member
liammiller

Latest Threads

Top