Comparing if two objects are of same type without RTTI

Discussion in 'C++' started by vj, Apr 20, 2011.

  1. vj

    vj Guest

    Hi All,

    Just realized that one can directly compare the vptr of two objects to
    check if they belong to the same class or not. Below is the example
    code:

    <code>
    #define VPTR(__X__) (*((int*)&(__X__)))

    class A{
    public:
    virtual ~A(){}
    };
    class B{
    public:
    virtual ~B(){}
    };

    int main(){
    A a1,a2;
    B b1;
    ASSERT( VPTR(a1)==VPTR(a2) );
    ASSERT( VPTR(a1)!=VPTR(b) );
    }
    </code>

    This makes it possible to check if two objects are of same type or not
    even if RTTI support is not available (like we have on some embedded
    platforms). I do understand that this method is only applicable if the
    said classes have a vtable. But I am not sure if there are any other
    gotchas' that I am overlooking. Whats your take on this.

    Thanks,
    ~Vaibhav
     
    vj, Apr 20, 2011
    #1
    1. Advertising

  2. vj

    SG Guest

    On 20 Apr., 12:48, vj wrote:
    >
    > Just realized that one can directly compare the vptr of two objects


    The what? The C++ ISO standard does not say anything about a "vptr".
    (And no, I don't want you to explain to me how virtual functions are
    typically implemented.)

    > [ ... horrible non-portable hack ... ]
    >
    > This makes it possible to check if two objects are of same type or not
    > even if RTTI support is not available (like we have on some embedded
    > platforms). I do understand that this method is only applicable if the
    > said classes have a vtable. But I am not sure if there are any other
    > gotchas' that I am overlooking. Whats your take on this.


    I think I answered that already by summarizing your code with
    "horrible non-portable hack". I don't know what I would do in your
    position. I guess I would first question the design that required me
    to use typeid. If the design is ok (which is hard to tell without any
    more details) I'd consider filing a complaint with the compiler vendor
    about the lack of RTTI.

    SG
     
    SG, Apr 20, 2011
    #2
    1. Advertising

  3. On 4/20/2011 6:48 AM, vj wrote:
    > Just realized that one can directly compare the vptr of two objects to
    > check if they belong to the same class or not.


    That requires that there *is* such a thing as 'vptr' in both objects.

    > Below is the example
    > code:
    >
    > <code>
    > #define VPTR(__X__) (*((int*)&(__X__)))


    BTW, the use of double underscores in a name is reserved by the
    implementation (even if it's a name of a formal argument of a macro).
    There is *really* no need for those double underscores here.

    >
    > class A{
    > public:
    > virtual ~A(){}
    > };
    > class B{
    > public:
    > virtual ~B(){}
    > };


    What's going to happen if

    class C {
    A a; // contained
    };

    and you compare a 'C' to an 'A'?

    >
    > int main(){
    > A a1,a2;
    > B b1;
    > ASSERT( VPTR(a1)==VPTR(a2) );
    > ASSERT( VPTR(a1)!=VPTR(b) );
    > }
    > </code>
    >
    > This makes it possible to check if two objects are of same type or not
    > even if RTTI support is not available (like we have on some embedded
    > platforms). I do understand that this method is only applicable if the
    > said classes have a vtable. But I am not sure if there are any other
    > gotchas' that I am overlooking. Whats your take on this.


    See above.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Apr 20, 2011
    #3
  4. vj

    gwowen Guest

    On Apr 20, 1:08 pm, Victor Bazarov <> wrote:
    > On 4/20/2011 6:48 AM, vj wrote:
    >
    > > Just realized that one can directly compare the vptr of two objects to
    > > check if they belong to the same class or not.

    >
    > That requires that there *is* such a thing as 'vptr' in both objects.
    >
    >  > Below is the example
    >
    > > code:

    >
    > > <code>
    > > #define VPTR(__X__)   (*((int*)&(__X__)))

    >
    > BTW, the use of double underscores in a name is reserved by the
    > implementation (even if it's a name of a formal argument of a macro).
    > There is *really* no need for those double underscores here.
    >
    >
    >
    > > class A{
    > > public:
    > >      virtual ~A(){}
    > > };
    > > class B{
    > > public:
    > >      virtual ~B(){}
    > > };

    >
    > What's going to happen if
    >
    >     class C {
    >        A a; // contained
    >     };
    >
    > and you compare a 'C' to an 'A'?


    Or if sizeof(int)!= sizeof(_vptr)

    (obviously, presupposing the usual implementation)
     
    gwowen, Apr 20, 2011
    #4
  5. vj

    gwowen Guest

    On Apr 20, 1:31 pm, gwowen <> wrote:

    > Or if sizeof(int)!= sizeof(_vptr)
    >
    > (obviously, presupposing the usual implementation)


    class foo {
    public:
    int x;
    virtual void reset() {x=0;};
    virtual void increment() { x += 1;} ;
    }

    class tagged_foo : public foo
    {
    public:
    std::string tag;
    }

    Given the "as is" rule, I can't see any reason why, on an
    implementation lacking RTTI, that the vptr for tagged_foo should be
    different for foo, since I don't override any of the virtual
    functions.

    So even as a non-standard, implementation-specific hack, the compiler
    may decide to undermine you, in the name of efficiency.
     
    gwowen, Apr 20, 2011
    #5
  6. vj

    vj Guest

    Thanks for the reply,

    @SG
    >I guess I would first question the design that required me
    >to use typeid. If the design is ok (which is hard to tell without any
    >more details) I'd consider filing a complaint with the compiler vendor
    >about the lack of RTTI.


    This is simply a test code. There is nothing production about it. I
    simply wanted to test an idea thats all.

    @ Victor Bazarov
    >BTW, the use of double underscores in a name is reserved by the
    >implementation (even if it's a name of a formal argument of a macro).
    >There is *really* no need for those double underscores here.


    Please bear with the use of __X__ I wasnt aware that the use of
    double underscore was reserved even for formal arguments of a macro.
    Thanks for pointing this out.


    @gwowen
    >Or if sizeof(int)!= sizeof(_vptr)


    Yes you are right. But if this code is specifically for some platform
    where sizeof(int) == sizeof(_vptr) (like IA32) then i guess this hack
    is workable, though there is nothing portable about it.


    >What's going to happen if
    > class C {
    > A a; // contained
    > };
    >and you compare a 'C' to an 'A'?


    >class tagged_foo : public foo
    >{
    >public:
    > std::string tag;
    >}

    This two really kills the generic use of this hack. Thanks for
    pointing this out. I am more upset for the first one which definitely
    will give false positives. Though I still think that this hack can be
    used on classes residing on the same level of a class hierarchy and
    its known that they don't have any associations with each other.

    Thanks for your comments guys,
    ~Vaibhav
     
    vj, Apr 20, 2011
    #6
  7. vj

    gwowen Guest

    On Apr 20, 1:46 pm, gwowen <> wrote:

    > class tagged_foo : public foo
    > {
    > public:
    >   std::string tag;
    >
    > }
    >
    > Given the "as is" rule, I can't see any reason why, on an
    > implementation lacking RTTI, that the vptr for tagged_foo should be
    > different for foo, since I don't override any of the virtual
    > functions.


    OK, the destructor... but replace std::string with a POD type that
    doesn't need destructificating, and I think the point still holds.
     
    gwowen, Apr 20, 2011
    #7
  8. vj

    vj Guest

    On Apr 20, 6:44 pm, gwowen <> wrote:
    > On Apr 20, 1:46 pm, gwowen <> wrote:
    >
    > > class tagged_foo : public foo
    > > {
    > > public:
    > >   std::string tag;

    >
    > > }

    >
    > > Given the "as is" rule, I can't see any reason why, on an
    > > implementation lacking RTTI, that the vptr for tagged_foo should be
    > > different for foo, since I don't override any of the virtual
    > > functions.

    >
    > OK, the destructor... but replace std::string with a POD type that
    > doesn't need destructificating, and I think the point still holds.


    I tried this definition

    class C:public A{
    int j;
    };

    And it seems that MS C/C++ v14.0 compiler still allocates a different
    vtable for class C , even though it could have reused the existing
    vtable from class A. This was done with maximum optimizations on (/
    Ox). I havent tried GCC though but seems like this hack works atleast
    on MSVC .

    ~Vaibhav
     
    vj, Apr 20, 2011
    #8
  9. Am 20.04.2011 15:52, schrieb vj:
    > On Apr 20, 6:44 pm, gwowen<> wrote:
    >> On Apr 20, 1:46 pm, gwowen<> wrote:
    >>
    >>> class tagged_foo : public foo
    >>> {
    >>> public:
    >>> std::string tag;

    >>
    >>> }

    >>
    >>> Given the "as is" rule, I can't see any reason why, on an
    >>> implementation lacking RTTI, that the vptr for tagged_foo should be
    >>> different for foo, since I don't override any of the virtual
    >>> functions.

    >>
    >> OK, the destructor... but replace std::string with a POD type that
    >> doesn't need destructificating, and I think the point still holds.

    >
    > I tried this definition
    >
    > class C:public A{
    > int j;
    > };
    >
    > And it seems that MS C/C++ v14.0 compiler still allocates a different
    > vtable for class C , even though it could have reused the existing
    > vtable from class A. This was done with maximum optimizations on (/
    > Ox). I havent tried GCC though but seems like this hack works atleast
    > on MSVC .


    MSVC can't reuse the vtables for this, because the vtable also contains
    the RTTI pointer. If you have a compiler without (or with disabled) RTTI
    support, the vtables could be merged, because no virtual function in
    class A has changed in class C.

    You should test if this hack really works with your target compiler on
    your target platform; but I advise not to use it in production code.

    Instead, you should use virtual functions (think Visitor Pattern) or
    integer IDs (or enums) per class.

    --
    Thomas
     
    Thomas J. Gritzan, Apr 20, 2011
    #9
  10. vj

    Noah Roberts Guest

    On 4/20/2011 5:08 AM, Victor Bazarov wrote:
    > On 4/20/2011 6:48 AM, vj wrote:
    >> Just realized that one can directly compare the vptr of two objects to
    >> check if they belong to the same class or not.

    >
    > That requires that there *is* such a thing as 'vptr' in both objects.
    >
    > > Below is the example
    >> code:
    >>
    >> <code>
    >> #define VPTR(__X__) (*((int*)&(__X__)))


    > What's going to happen if
    >
    > class C {
    > A a; // contained
    > };
    >
    > and you compare a 'C' to an 'A'?


    I think multiple inheritance would toss it off too.


    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Apr 20, 2011
    #10
  11. vj

    vj Guest

    On Apr 20, 7:03 pm, "Thomas J. Gritzan" <>
    wrote:
    > Am 20.04.2011 15:52, schrieb vj:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > On Apr 20, 6:44 pm, gwowen<>  wrote:
    > >> On Apr 20, 1:46 pm, gwowen<>  wrote:

    >
    > >>> class tagged_foo : public foo
    > >>> {
    > >>> public:
    > >>>    std::string tag;

    >
    > >>> }

    >
    > >>> Given the "as is" rule, I can't see any reason why, on an
    > >>> implementation lacking RTTI, that the vptr for tagged_foo should be
    > >>> different for foo, since I don't override any of the virtual
    > >>> functions.

    >
    > >> OK, the destructor... but replace std::string with a POD type that
    > >> doesn't need destructificating, and I think the point still holds.

    >
    > > I tried this definition

    >
    > > class C:public A{
    > >      int j;
    > > };

    >
    > > And it seems that MS C/C++ v14.0 compiler still allocates a different
    > > vtable for class C , even though it could have reused the existing
    > > vtable from class A. This was done with maximum optimizations on (/
    > > Ox). I havent tried GCC though but seems like this hack works atleast
    > > on MSVC .

    >
    > MSVC can't reuse the vtables for this, because the vtable also contains
    > the RTTI pointer. If you have a compiler without (or with disabled) RTTI
    > support, the vtables could be merged, because no virtual function in
    > class A has changed in class C.
    >
    > You should test if this hack really works with your target compiler on
    > your target platform; but I advise not to use it in production code.
    >
    > Instead, you should use virtual functions (think Visitor Pattern) or
    > integer IDs (or enums) per class.
    >
    > --
    > Thomas


    I again tried this definition with maximum optimizations and disabling
    RTTI (/GR-)
    class C:public A{
    int j;
    };

    And it seems that MS C/C++ v14.0 compiler still allocates a different
    vtable for class C , even though it could have reused the existing
    vtable from class A.
     
    vj, Apr 21, 2011
    #11
  12. vj

    vj Guest

    On Apr 20, 9:20 pm, Noah Roberts <> wrote:
    > On 4/20/2011 5:08 AM, Victor Bazarov wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > On 4/20/2011 6:48 AM, vj wrote:
    > >> Just realized that one can directly compare the vptr of two objects to
    > >> check if they belong to the same class or not.

    >
    > > That requires that there *is* such a thing as 'vptr' in both objects.

    >
    > >  > Below is the example
    > >> code:

    >
    > >> <code>
    > >> #define VPTR(__X__) (*((int*)&(__X__)))

    > > What's going to happen if

    >
    > > class C {
    > > A a; // contained
    > > };

    >
    > > and you compare a 'C' to an 'A'?

    >
    > I think multiple inheritance would toss it off too.
    >
    > --http://crazycpp.wordpress.com


    Surely it will also the contained object pattern as described by
    gwowen. So overall to me it seems that though this hack surely is non
    portable and has lot many issue but under certain strict scenarios
    this can serve as a good alternative to using rtti which can be slow.

    ~Vaibhav
     
    vj, Apr 21, 2011
    #12
  13. vj

    gwowen Guest

    On Apr 21, 8:56 am, vj <> wrote:

    > I again tried this definition with maximum optimizations and disabling
    > RTTI (/GR-)
    > class C:public A{
    >     int j;
    >
    > };
    >
    > And it seems that MS C/C++ v14.0 compiler still allocates a different
    > vtable for class C , even though it could have reused the existing
    > vtable from class A.


    But even then, the only guarantee is "it worked today, with these
    compiler switches". Compile for space [likely in an embedded app], and
    the linker may be smart enough to merge two identical read-only
    structures. Upgrade the linker, or even recompile the linker with link-
    time-optimizations activated, and a similar thing can happen.

    Hell, for an embedded app, a compiler/linker may be able to deduce the
    dispatch of all function calls at compile time, and the unreferred-to-
    vtable won't even get linked - particularly for a class in an
    anonymous namespace, say.

    And the hack may not work on this compiler version VC++ v14.0 on
    x86_64, because sizeof(int) == 4, on x86_64, whereas sizeof(void*) !=
    8.

    So yes, the hack might work today, on one one platform (true of all
    hacks, or whats the point?) but relying on it is really, really not a
    good idea. If you need cheap RTTI-type facilities, there are better
    "hacks".
     
    gwowen, Apr 21, 2011
    #13
  14. vj <> wrote:
    > This makes it possible to check if two objects are of same type or not
    > even if RTTI support is not available (like we have on some embedded
    > platforms). I do understand that this method is only applicable if the
    > said classes have a vtable. But I am not sure if there are any other
    > gotchas' that I am overlooking. Whats your take on this.


    Besides being horribly non-portable (which should go without saying),
    it doesn't work in cases of multiple inheritance, even if you limit
    yourself to just using "interfaces" like in many other OO languages
    (which means that nobody should have any rational or philosophical
    objections to MI in this case).

    If C inherits from both A and B, comparing the (assumed) vptr at
    the beginning of an object of type C with an object of type B will
    obviously not produce the same result. In fact, most probably it
    will not work when comparing objects of type C and A either. A dynamic
    cast will, however, work properly in this situation.
     
    Juha Nieminen, Apr 21, 2011
    #14
  15. vj

    Noah Roberts Guest

    On 4/21/2011 12:59 AM, vj wrote:
    > On Apr 20, 9:20 pm, Noah Roberts<> wrote:
    >> On 4/20/2011 5:08 AM, Victor Bazarov wrote:
    >>
    >>
    >>
    >>
    >>
    >>
    >>
    >>
    >>
    >>> On 4/20/2011 6:48 AM, vj wrote:
    >>>> Just realized that one can directly compare the vptr of two objects to
    >>>> check if they belong to the same class or not.

    >>
    >>> That requires that there *is* such a thing as 'vptr' in both objects.

    >>
    >>> > Below is the example
    >>>> code:

    >>
    >>>> <code>
    >>>> #define VPTR(__X__) (*((int*)&(__X__)))
    >>> What's going to happen if

    >>
    >>> class C {
    >>> A a; // contained
    >>> };

    >>
    >>> and you compare a 'C' to an 'A'?

    >>
    >> I think multiple inheritance would toss it off too.
    >>
    >> --http://crazycpp.wordpress.com

    >
    > Surely it will also the contained object pattern as described by
    > gwowen. So overall to me it seems that though this hack surely is non
    > portable and has lot many issue but under certain strict scenarios
    > this can serve as a good alternative to using rtti which can be slow.


    If you're worried about the "slowness" of RTTI (I've never noticed it on
    my profiler to tell the truth) then you can simply use an alternative
    mechanism. Preferably something that will consistently work.

    The tag thunking mechanism in
    http://www.artima.com/cppsource/cooperative_visitor.html for
    example...AFAICT it only uses standard, well-defined behavior and does
    everything you might get from your method.

    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Apr 21, 2011
    #15
    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. Alexander Block
    Replies:
    26
    Views:
    2,823
    Pete Becker
    May 29, 2004
  2. Derek
    Replies:
    4
    Views:
    520
    Marcin Kalicinski
    Mar 23, 2005
  3. Vbfoo Bar
    Replies:
    1
    Views:
    340
    Benjamin Niemann
    Sep 14, 2004
  4. shuisheng
    Replies:
    15
    Views:
    549
    Grizlyk
    Dec 2, 2006
  5. mike
    Replies:
    1
    Views:
    324
    Mark Space
    Mar 3, 2009
Loading...

Share This Page