typeid and dynamic_cast, gcc 3.3

A

Andreas Sch.

Hello,

I had been quite suprised by the
following little program:

---- cut ----

#include "iostream.h"

class base {
  public:
  base(){}
  virtual ~base(){};
  void printType(base * obj);
};

class derived : public base {
  public:
  virtual void doIt()
  {
    printType(this);
  }  
};

void base::printType(base * obj) {
  cout << "type is " << typeid(obj).name() << endl;
  cout << dynamic_cast<derived *>(obj) << endl;
}

int main(int argc, char * argv[]) {
  derived myObj;
  myObj.doIt();
}

---- cut ----

It prints:

type is P4base
0xbfffec00

My expectation was to see "derived" for
the type name.

And even if it is identified as "base"
the RTTI should not be able to dynamic-cast
it to a derived object which it is reported
not to be.

Tested with gcc 3.3 and 3.3.2.

Somebody able to enlighten me?

Greetings,
Andreas
 
A

Asfand Yar Qazi

Andreas said:
Hello,

I had been quite suprised by the
following little program:

---- cut ----

#include "iostream.h"

class base {
public:
base(){}
virtual ~base(){};
void printType(base * obj);
};

class derived : public base {
public:
virtual void doIt()
{
printType(this);
}
};

void base::printType(base * obj) {
cout << "type is " << typeid(obj).name() << endl;

This isn't a virtual function, so it will be called with type of 'this'
set to "base", even though it was called from a virtual function
(virtual-ness doesn't pass along the calling sequence, its on a
per-function basis.) Dynamic-casting

cout << dynamic_cast<derived *>(obj) << endl;

I don't see the purpose of doing this: it just prints out the pointer
value. Did you forget to typeid() it?
}

int main(int argc, char * argv[]) {
derived myObj;
myObj.doIt();
}

---- cut ----
 
G

Gianni Mariani

Andreas said:
Hello,

I had been quite suprised by the
following little program:

---- cut ----

#include "iostream.h"
this header is not standard - use #include said:
class base {
public:
base(){}
virtual ~base(){};
^^^^^^^^ ';' not needed
void printType(base * obj);
};

class derived : public base {
public:
virtual void doIt()
{
printType(this);
}
};

void base::printType(base * obj) {
cout << "type is " << typeid(obj).name() << endl;

^^^^^^^^^^^^^^^ ... this is the same as

cout << "type is " << typeid( (base *) 0 ).name() << endl;


cout << dynamic_cast<derived *>(obj) << endl;
}

int main(int argc, char * argv[]) {
derived myObj;
myObj.doIt();
}

---- cut ----

It prints:

type is P4base
0xbfffec00

My expectation was to see "derived" for
the type name.

And even if it is identified as "base"
the RTTI should not be able to dynamic-cast
it to a derived object which it is reported
not to be.

Tested with gcc 3.3 and 3.3.2.

Somebody able to enlighten me?

Try this:

class derived;

#include <iostream>
using namespace std;

class base {
public:
base(){}
virtual ~base(){}

template <typename T>
void printType(T * obj)
{
cout << "type is " << typeid(obj).name() << endl;
cout << dynamic_cast<derived *>(obj) << endl;
}
};

class derived : public base {
public:
virtual void doIt()
{
printType(this);
}
};


int main(int argc, char * argv[]) {
derived myObj;
myObj.doIt();
}
 
A

Andreas Sch.

Asfand said:
This isn't a virtual function, so it will be called with type of 'this'
set to "base", even though it was called from a virtual function
(virtual-ness doesn't pass along the calling sequence, its on a
per-function basis.) Dynamic-casting

Lets see if I got it: typeid does not evaluate the
type information in memory but depends on the type
of the "obj" pointer (and not on what it is pointing to).
I don't see the purpose of doing this: it just prints out the pointer
value. Did you forget to typeid() it?

I just wanted to see if the dynamic_cast fails and
delivers 0x0. I expected it to fail since the typeid-line
printed "base" and not "derived".

Thanks for your answer!
Andreas
 
A

Andreas Sch.

Gianni said:
this header is not standard - use #include <iostream>

Ok...

^^^^^^^^ ';' not needed

Oops, sure.
^^^^^^^^^^^^^^^ ... this is the same as

cout << "type is " << typeid( (base *) 0 ).name() << endl;

So typeid delivers the type of the pointer,
not the object.
(...)
Try this:
(...)

That worked. Thank you.

I have been hunting a strange problem in a program
which fails at a dynamic_cast. To debug that situation
I heavily used typeid() and was quite suprised about
its different behavior.

If I am able to shorten the program to a small
example and still produce the same behavior I'll
write that here, too.

Greetings,
Andreas
 
S

Sharad Kala

Andreas Sch. said:
Lets see if I got it: typeid does not evaluate the
type information in memory but depends on the type
of the "obj" pointer (and not on what it is pointing to).

This is a quote from msdn -
<Quote>
If the expression points to a base class type, yet the object is actually of a
type derived from that base class, a type_info reference for the derived class
is the result. The expression must point to a polymorphic type (a class with
virtual functions). Otherwise, the result is the type_info for the static class
referred to in the expression. Further, the pointer must be dereferenced so that
the object it points to is used. Without dereferencing the pointer, the result
will be the type_info for the pointer, not what it points to.
</Quote>

Best wishes,
Sharad

Disclaimer : I know msdn isn't totally accurate at places but not here ;-)
 
S

Sharad Kala

</snip>
You don't seem to include typeinfo in your code.

Quote from Section 5.2.8.6 of the standard.
" If the header <typeinfo> is not included prior to a use of typeid, the program
is ill-formed. "

Best wishes,
Sharad
 
R

Rolf Magnus

Andreas said:
So typeid delivers the type of the pointer,
not the object.

Yes. That's what you asked for. If you provide a pointer to typeid(), it
will tell you that it's a pointer ;-)
If you want info about what the pointer points to, you need to
dereference, i.e typeid(*obj).
 
A

Andreas Sch.

Hi!

First of all, thank you all for your valuable
answers to my previous question!

Again, I have a short program illustrating my
(next) problem:

--- snipp ---

#include <typeinfo>
#include <iostream>

class Base
{
public:
Base(){};
virtual ~Base(){};
void calledMethod( Base * a_Base );
};

class Derived : Base
{
public:
Derived() : Base(){};
virtual ~Derived(){};
virtual void callingMethod();
};

void Base::calledMethod( Base * a_base )
{
std::cout << "Parameter is of type \"" << typeid(*a_base).name()
<< "\" at address " << dynamic_cast<Derived *>(a_base)
<< std::endl;
}

void Derived::callingMethod( )
{
std::cout << "I am of type \"" << typeid(*this).name()
<< "\" at address " << dynamic_cast<Derived *>(this)
<< std::endl;
calledMethod( this );
}

int main(int argc, char * argv[])
{
Derived myDerived;
myDerived.callingMethod();
}

/* Program output:

I am of type "7Derived" at address 0xbfffea90
Parameter is of type "7Derived" at address 0

*/

--- snipp ---

The question is: Why is the dynamic_cast in calledMethod()
failing?

RU,
Andreas
 
R

Rolf Magnus

Ron said:
You want
class Derived : public Base

I can't even understand why this compiles.

I don't know whether it should compile or not, but this probably is the
reason why it doesn't work. If you derive virtually, Base is not an
accessible base class of Derived.
 
R

Ron Natalie

Rolf Magnus said:
I don't know whether it should compile or not, but this probably is the
reason why it doesn't work. If you derive virtually, Base is not an
accessible base class of Derived.
You mean privately, not virtually.

The program is ill-formed because you can't call the base class "calledMethod"
function since it's not accessible.
 
M

Michael Mellor

Ron said:
You mean privately, not virtually.

The program is ill-formed because you can't call the base class "calledMethod"
function since it's not accessible.
It is not ill-formed, to quote 11.2.1 from the standard:
"...If a class is declared to be a base class for another class using
the private access specifier, the public and protected members of the
base class are accessible as private members of the derived class."

Therefore the following code is legal:
class A {
public:
void A_f ( ) { }
};

class B : A {
public:
void f ( ) { A_f ( ); }
};

Michael Mellor
 
R

Rolf Magnus

Ron said:
You mean privately, not virtually.

Of course. Sorry.
The program is ill-formed because you can't call the base class
"calledMethod" function since it's not accessible.

calledMethod is only called by Derived::callingMethod, from where it is
accessible.
 
R

Ron Natalie

Rolf Magnus said:
calledMethod is only called by Derived::callingMethod, from where it is
accessible.

It is NOT accessible. Base is inherited privately. NONE of it's members
are accessible.
 
R

Rolf Magnus

Ron said:
It is NOT accessible. Base is inherited privately. NONE of it's
members are accessible.

....from the "outside world". But from Derived they are. If you derive
privately, public and protected members of Base are private in Derived,
and so they can be called from Derived's member functions. If that
weren't the case, deriving privatly would just be another way of not
deriving at all. Only members that are private in Base are not
accessible to Derived, since private members can only be accessed by
the class itself and to friends.
 
M

Michael Mellor

Ron said:
It is NOT accessible. Base is inherited privately. NONE of it's members
are accessible.
The derived class can access the base class's public methods or else how
would private inheritence ever be useful?

Michael Mellor
 
A

Andreas Schallenberg

Ron said:
You mean privately, not virtually.
(...)

I tried using public here and yes, it works
as desired.

When deriving privately the outside world should have
problems accessing the base class' members but what
about having a reference to the object?
I may always have a reference to an object which has
only private members (attributes and methods).
In this example the base class tries to cast
a pointer so that it points to a derived object.
Why is this failing?

In other words, I see the effect of deriving public
and know that it should hide the base class members
from being accessed from outside but why does this
affect the dynamic cast?

Greetings,
Andreas
 
J

Janusz Szpilewski

Andreas said:
In this example the base class tries to cast
a pointer so that it points to a derived object.
Why is this failing?

dynamic_cast will only succeed if the pointed base class object is
inherited via public inheritance otherwise it fails (C++ std 5.2.7/8).
In such a case use static_cast or C style cast.

Regards,
Janusz
 

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,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top