typeid and dynamic_cast, gcc 3.3

Discussion in 'C++' started by Andreas Sch., Jan 23, 2004.

  1. Andreas Sch.

    Andreas Sch. Guest

    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
     
    Andreas Sch., Jan 23, 2004
    #1
    1. Advertising

  2. Andreas Sch. wrote:
    > 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 ----




    --
    http://www.it-is-truth.org/
     
    Asfand Yar Qazi, Jan 23, 2004
    #2
    1. Advertising

  3. Andreas Sch. wrote:
    > Hello,
    >
    > I had been quite suprised by the
    > following little program:
    >
    > ---- cut ----
    >
    > #include "iostream.h"

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

    >
    > 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();
    }
     
    Gianni Mariani, Jan 23, 2004
    #3
  4. Andreas Sch.

    Andreas Sch. Guest

    Asfand Yar Qazi wrote:
    >> (...)
    >> 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
    >


    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).

    >
    >> 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?
    >


    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
     
    Andreas Sch., Jan 23, 2004
    #4
  5. Andreas Sch.

    Andreas Sch. Guest

    Gianni Mariani wrote:
    >> (...)
    >> #include "iostream.h"

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


    Ok...

    >>
    >> class base {
    >> (...)
    >> virtual ~base(){};

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


    Oops, sure.

    >> (...)
    >> 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;
    >


    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
     
    Andreas Sch., Jan 23, 2004
    #5
  6. Andreas Sch.

    Sharad Kala Guest

    "Andreas Sch." <> wrote in message
    news:buqtp6$l9b28$-berlin.de...
    > Asfand Yar Qazi wrote:
    > >> (...)
    > >> 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
    > >

    >
    > 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 ;-)
     
    Sharad Kala, Jan 23, 2004
    #6
  7. Andreas Sch.

    Sharad Kala Guest

    "Sharad Kala" <> wrote in message
    news:bur0bc$2vqka$-berlin.de...
    >

    </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
     
    Sharad Kala, Jan 23, 2004
    #7
  8. Andreas Sch.

    Rolf Magnus Guest

    Andreas Sch. wrote:

    >>> 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;
    >>

    >
    > 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).
     
    Rolf Magnus, Jan 23, 2004
    #8
  9. Andreas Sch.

    Andreas Sch. Guest

    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
     
    Andreas Sch., Jan 29, 2004
    #9
  10. Andreas Sch.

    Ron Natalie Guest

    "Andreas Sch." <> wrote in message news:bvb9ov$pv9p5$-berlin.de...
    > class Derived : Base


    You want
    class Derived : public Base

    I can't even understand why this compiles.
     
    Ron Natalie, Jan 29, 2004
    #10
  11. Andreas Sch.

    Rolf Magnus Guest

    Ron Natalie wrote:

    >> class Derived : Base

    >
    > 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.
     
    Rolf Magnus, Jan 29, 2004
    #11
  12. Andreas Sch.

    Ron Natalie Guest

    "Rolf Magnus" <> wrote in message news:bvbf9b$v87$05$-online.com...
    > Ron Natalie wrote:
    >
    > >> class Derived : Base

    > >
    > > 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.
    >

    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.
     
    Ron Natalie, Jan 29, 2004
    #12
  13. Ron Natalie wrote:
    > "Rolf Magnus" <> wrote in message news:bvbf9b$v87$05$-online.com...
    >
    >>Ron Natalie wrote:
    >>
    >>
    >>>>class Derived : Base
    >>>
    >>>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.
    >>

    >
    > 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
     
    Michael Mellor, Jan 29, 2004
    #13
  14. Andreas Sch.

    Rolf Magnus Guest

    Ron Natalie wrote:

    >
    > "Rolf Magnus" <> wrote in message
    > news:bvbf9b$v87$05$-online.com...
    >> Ron Natalie wrote:
    >>
    >> >> class Derived : Base
    >> >
    >> > 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.
    >>

    > 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.
     
    Rolf Magnus, Jan 29, 2004
    #14
  15. Andreas Sch.

    Ron Natalie Guest

    "Rolf Magnus" <> wrote in message news:bvbikt$v6a$00$-online.com...
    > 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.
     
    Ron Natalie, Jan 29, 2004
    #15
  16. Andreas Sch.

    Rolf Magnus Guest

    Ron Natalie wrote:

    > "Rolf Magnus" <> wrote in message
    > news:bvbikt$v6a$00$-online.com...
    >> 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.


    ....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.
     
    Rolf Magnus, Jan 29, 2004
    #16
  17. Ron Natalie wrote:

    > "Rolf Magnus" <> wrote in message news:bvbikt$v6a$00$-online.com...
    >
    >>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.
    >

    The derived class can access the base class's public methods or else how
    would private inheritence ever be useful?

    Michael Mellor
     
    Michael Mellor, Jan 29, 2004
    #17
  18. Ron Natalie schrieb:
    > "Rolf Magnus" <> wrote (...):
    >> Ron Natalie wrote:
    >>
    >> >> class Derived : Base
    >> >
    >> > You want
    >> > class Derived : public Base
    >> >

    >> (...)
    >> 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.
    > (...)


    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
     
    Andreas Schallenberg, Jan 29, 2004
    #18
  19. Andreas Schallenberg wrote:

    > 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
     
    Janusz Szpilewski, Jan 29, 2004
    #19
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dave Theese

    typeid and polymorphic classes

    Dave Theese, Sep 8, 2003, in forum: C++
    Replies:
    5
    Views:
    563
    Govindan
    Sep 8, 2003
  2. Jamie Burns
    Replies:
    11
    Views:
    8,971
    Nick Hounsome
    Jan 29, 2004
  3. Max

    template and typeid

    Max, Jun 30, 2004, in forum: C++
    Replies:
    3
    Views:
    2,868
    Prateek R Karandikar
    Jun 30, 2004
  4. Ganesh
    Replies:
    3
    Views:
    503
    Rolf Magnus
    May 10, 2005
  5. flopbucket

    dynamic_cast and typeid

    flopbucket, Aug 15, 2007, in forum: C++
    Replies:
    4
    Views:
    534
Loading...

Share This Page