Q) Identifying the correct data type at run time (RTTI anddynamic_cast)



 DEVELOP > c-Plus-Plus > Q) Identifying the correct data type at run time (RTTI anddynamic_cast)

LINK TO THIS PAGE  


rating :  0   |  0


  Page 1 of 1

1

 
Topic: DEVELOP > c-Plus-Plus
User: "Generic Usenet Account"
Date: 12 Dec 2007 02:40:09 PM
Object: Q) Identifying the correct data type at run time (RTTI anddynamic_cast)
I ran a small experiment involving RTTI and dynamic casting.
Basically what I did was to cast a base class pointer to a derived
type (yes, I know that is not kosher). I then performed
dynamic_casting and I invoked RTTI. In both instances, the run time
environment did not pick up the fact that what I was claiming to be a
derived pointer was in fact the base pointer. However, when I invoked
a virtual method using the ostensibly derived class pointer (which was
in reality the base class pointer), it was the base class method that
got invoked (and correctly so). Is this the correct behavior, or is
it the quirk of my compiler (gcc version 3.3.1)?
I know that I am a nobody, but here is what I was expecting:
dynamic_casting: Since the pointer was really to the base class, and
not to the derived class, as claimed, dynamic_casting should have
picked that up and returned NULL.
RTTI: The typeid for the pointer should have been that of the base,
even though I claimed that it was the derived class pointer.
My sample code snippet follows:
//////////////////////////////////////////////////////////
#include <iostream>
#include <typeinfo>
#include <string>
using namespace std;
#define TYPEID(x) cout << #x << ": " << typeid(x).name() << endl;
class Base
{
public:
Base() {}
~Base() {}
virtual void testMethod (int x) {cout << "Passed value " << x << "
to the base class method\n";}
};
class Derived: public Base
{
public:
Derived() {}
~Derived() {}
virtual void testMethod (int x) {cout << "Passed value " << x << "
to the derived class method\n";}
};
template<typename T>
void
validateType(const string& label, T* ptr)
{
T* typePtr = dynamic_cast<T*>(ptr);
if(ptr)
cout << "Type match";
else
cout << "Type mismatch";
cout << " for " << label << endl;
}
main()
{
Base *basePtr1 = new Base;
Base *basePtr2 = new Base;
Derived *derivedPtr = static_cast<Derived *>(basePtr2);
basePtr1->testMethod(25);
derivedPtr->testMethod(25);
validateType<Base>("basePtr", basePtr1);
validateType<Derived>("Derived", derivedPtr);
TYPEID(basePtr1);
TYPEID(basePtr2);
TYPEID(derivedPtr);
return 0;
}
//////////////////////////////////////////////////////////
Thanks,
Song
.

User: "Victor Bazarov"

Title: Re: Q) Identifying the correct data type at run time (RTTI and dynamic_cast) 12 Dec 2007 02:53:16 PM
Generic Usenet Account wrote:

I ran [..]

//////////////////////////////////////////////////////////

#include <iostream>
#include <typeinfo>
#include <string>

using namespace std;

#define TYPEID(x) cout << #x << ": " << typeid(x).name() << endl;

class Base
{
public:
Base() {}
~Base() {}

Probably should be
virtual ~Base() {}

virtual void testMethod (int x) {cout << "Passed value " << x << "
to the base class method\n";}

Newline in a string constant. Try to put more linebreaks in right
places when posting code.

};

class Derived: public Base
{
public:
Derived() {}
~Derived() {}
virtual void testMethod (int x) {cout << "Passed value " << x << "
to the derived class method\n";}
};

template<typename T>
void
validateType(const string& label, T* ptr)
{
T* typePtr = dynamic_cast<T*>(ptr);
if(ptr)

Here is your mistake! It should be
if (typePtr)

cout << "Type match";
else
cout << "Type mismatch";
cout << " for " << label << endl;
}


main()

int main()

{
Base *basePtr1 = new Base;
Base *basePtr2 = new Base;
Derived *derivedPtr = static_cast<Derived *>(basePtr2);

Since 'basePtr2' is NOT 'Derived', any attempt to use 'derivedPtr'
has undefined behaviour.


basePtr1->testMethod(25);
derivedPtr->testMethod(25);

validateType<Base>("basePtr", basePtr1);
validateType<Derived>("Derived", derivedPtr);

TYPEID(basePtr1);
TYPEID(basePtr2);
TYPEID(derivedPtr);
return 0;
}


//////////////////////////////////////////////////////////

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
.
User: ""

Title: Re: Q) Identifying the correct data type at run time (RTTI anddynamic_cast) 12 Dec 2007 03:14:00 PM
On Dec 12, 2:53 pm, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote:

Generic Usenet Account wrote:
Here is your mistake! It should be

if (typePtr)

Thanks. That is indeed a silly mistake. Any idea why RTTI is not
able to correctly identify the masquerading derived pointer (which is
actually the base type?)
.
User: "Victor Bazarov"

Title: Re: Q) Identifying the correct data type at run time (RTTI and dynamic_cast) 12 Dec 2007 03:48:42 PM
wrote:

On Dec 12, 2:53 pm, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote:

Generic Usenet Account wrote:


Here is your mistake! It should be

if (typePtr)


Thanks. That is indeed a silly mistake. Any idea why RTTI is not
able to correctly identify the masquerading derived pointer (which is
actually the base type?)

I am not sure I understand the question. 'dynamic_cast' should
return a null pointer if the object is not of the type to which
you're trying to cast your expression.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
.

User: ""

Title: Re: Q) Identifying the correct data type at run time (RTTI anddynamic_cast) 12 Dec 2007 03:20:31 PM
On Dec 12, 3:14 pm,
wrote:

On Dec 12, 2:53 pm, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote:

Generic Usenet Account wrote:
Here is your mistake! It should be


if (typePtr)


Thanks. That is indeed a silly mistake. Any idea why RTTI is not
able to correctly identify the masquerading derived pointer (which is
actually the base type?)

Even after fixing the silly mistake (thanks for pointing it out), the
behavior remains the same. Here's the sample output:
Passed value 25 to the base class method
Passed value 25 to the base class method
Type match for basePtr
Type match for Derived
basePtr1: P4Base
basePtr2: P4Base
derivedPtr: P7Derived
.
User: "Victor Bazarov"

Title: Re: Q) Identifying the correct data type at run time (RTTI and dynamic_cast) 12 Dec 2007 03:55:22 PM
wrote:

On Dec 12, 3:14 pm,

wrote:

On Dec 12, 2:53 pm, "Victor Bazarov" <v.Abaza...@comAcast.net> wrote:

Generic Usenet Account wrote:
Here is your mistake! It should be


if (typePtr)


Thanks. That is indeed a silly mistake. Any idea why RTTI is not
able to correctly identify the masquerading derived pointer (which is
actually the base type?)



Even after fixing the silly mistake (thanks for pointing it out), the
behavior remains the same.

The behaviour of your code was undefined since you 'static_cast' the
base class pointer to a derived class pointer when you have no right
to do so.
If you want to verify whether 'dynamic_cast' is working, here is
a simplified version:
template<class D, class B> bool verify(B* b) {
return dynamic_cast<D*>(b) != 0;
}
struct Base {
virtual ~Base() {}
};
struct Derived : Base {};
#include <iostream>
int main() {
Base *pReallyBase = new Base;
Base *pActuallyDerived = new Derived;
std::cout << "pReallyBase "
<< (verify<Derived>(pReallyBase) ? "is" : "isn't")
<< " in fact a Derived\n";
std::cout << "pActuallyDerived "
<< (verify<Derived>(pActuallyDerived) ? "is" : "isn't")
<< " in fact a Derived\n";
}
Output:
pReallyBase isn't in fact a Derived
pActuallyDerived is in fact a Derived

Here's the sample output:

Passed value 25 to the base class method
Passed value 25 to the base class method
Type match for basePtr
Type match for Derived
basePtr1: P4Base
basePtr2: P4Base
derivedPtr: P7Derived

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
.




User: "James Kanze"

Title: Re: Q) Identifying the correct data type at run time (RTTI anddynamic_cast) 13 Dec 2007 06:15:26 AM
On Dec 12, 9:40 pm, Generic Usenet Account <use...@sta.samsung.com>
wrote:

I ran a small experiment involving RTTI and dynamic casting.
Basically what I did was to cast a base class pointer to a derived
type (yes, I know that is not kosher). I then performed
dynamic_casting and I invoked RTTI. In both instances, the run time
environment did not pick up the fact that what I was claiming to be a
derived pointer was in fact the base pointer. However, when I invoked
a virtual method using the ostensibly derived class pointer (which was
in reality the base class pointer), it was the base class method that
got invoked (and correctly so). Is this the correct behavior, or is
it the quirk of my compiler (gcc version 3.3.1)?
I know that I am a nobody, but here is what I was expecting:
dynamic_casting: Since the pointer was really to the base class, and
not to the derived class, as claimed, dynamic_casting should have
picked that up and returned NULL.
RTTI: The typeid for the pointer should have been that of the base,
even though I claimed that it was the derived class pointer.
My sample code snippet follows:
//////////////////////////////////////////////////////////
#include <iostream>
#include <typeinfo>
#include <string>
using namespace std;
#define TYPEID(x) cout << #x << ": " << typeid(x).name() << endl;
class Base
{
public:
Base() {}
~Base() {}
virtual void testMethod (int x) {cout << "Passed value " << x << "
to the base class method\n";}
};

The destructor should almost certainly be virtual as well.

class Derived: public Base
{
public:
Derived() {}
~Derived() {}
virtual void testMethod (int x) {cout << "Passed value " << x << "
to the derived class method\n";}
};
template<typename T>
void
validateType(const string& label, T* ptr)
{
T* typePtr =3D dynamic_cast<T*>(ptr);

This line has exactly the same effect as:
T* typePtr =3D ptr ;
How could the dynamic_cast ever fail. You have a pointer to a
T, and you ask if it really points to a T. If you have a
pointer to a T, either 1) it is a null ponter, 2) it really
points to an object of type T, 3) it points to one past the end
of an array of T objects, or 4) it points to nothing in
particular. dynamic_cast only has defined behavior in the first
two cases. It can't be made to work (and probably isn't very
useful, given that objects in arrays cannot really be
polymorphic) in the third case, and even reading the pointer
results in undefined behavior in the last case.

if(ptr)
cout << "Type match";
else
cout << "Type mismatch";
cout << " for " << label << endl;
}
main()
{
Base *basePtr1 =3D new Base;
Base *basePtr2 =3D new Base;
Derived *derivedPtr =3D static_cast<Derived *>(basePtr2);

This is undefined behavior. You've lied to the compiler.
You've told it, unconditionally, that basePtr2 points to a
Derived. You've told the compiler that you know better.
Compilers don't like being lied to. They tend to get even with
you when you do. Except in exceptional cases, you should use
dynamic_cast when converting from pointer to base to pointer to
derived. If you used a dynamic_cast here, it would return a
null pointer. Using dynamic_cast is saying to the compiler: I
think this pointer really points to a Derived; please check, and
tell me if I'm wrong.

basePtr1->testMethod(25);
derivedPtr->testMethod(25);

This line is undefined behavior. You're using the result of
your lies to the compiler, which is undefined behavior. If you
replace the static_cast above with a dynamic_cast, you're
dereferencing a null pointer, which is also undefined behavior.

validateType<Base>("basePtr", basePtr1);
validateType<Derived>("Derived", derivedPtr);

Again: you pass derivedPtr to a function. That's undefined
behavior.

TYPEID(basePtr1);
TYPEID(basePtr2);
TYPEID(derivedPtr);

As above.

return 0;
}

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.


  Page 1 of 1

1

 


Related Articles
 

NEWER

pg.1232     pg.940     pg.716     pg.544     pg.412     pg.311     pg.234     pg.175     pg.130     pg.96     pg.70     pg.50     pg.35     pg.24     pg.16     pg.10     pg.6     pg.3     pg.1

OLDER