Some Questions about the C ++ virtual function table (G ++)

Source: Internet
Author: User

 
# Include <cstdio>
# Include <iostream>
# Include <typeinfo>
Using namespace std;
Class Point
{
Public:
Point ()
{
Cout <"Point constructor" <endl;
}
 
Virtual void func_hs ()
{
Cout <"Point: func_hs" <endl;
Printf ("the address of this -- func_hs: % p \ n", & Point: func_hs );
}
Virtual void func_prop ()
{
Cout <"Point: func_example" <endl;
Printf ("the address of this -- func_functions: % p \ n", & Point: func_functions );
}

Static void print ()
{
// Relative address, after the virtual table pointer. 0x4 0x8 0xc ---------> point to member
Printf ("& Point: x = % p \ n & Point: y = % p \ n & Point: z = % p \ n ",
& Point: x, & Point: y, & Point: z );
}

Void printThis ()
{
// Float *
Printf ("& this-> x = % p \ n & this-> y = % p \ n & this-> z = % p \ n ",
& This-> x, & this-> y, & this-> z );
}

Void printVt ()
{
Printf ("the address of object, this: % p \ nthe address of vt: % p \ n ",
This, (void *) * (int *) this );
}
Void callVtFuncs (int num = 2)
{
Cout <endl;

Typedef void (* Funp) (void );


For (int I = 0; I <num; I ++)
{
Funp funp = (Funp) * (int *) this + I );
Printf ("% p \ n", (int *) * (int *) this + I ));
Printf ("Point: callVtFuncs => address of this fun: % p \ n", funp );
If (I = 2 | I = 3)
{
Continue;
}
Funp ();
}
}

Void printVirtualFunAddress ()
{
Cout <endl;
Printf ("func_hs: % p \ nfunc_identifier: % p \ nfunc_zzzy: % p \ n ",
& Point: func_hs, & Point: func_functions,
& Point: func_zzzy );
Printf ("% p \ n", & Point: func_zzzy );

}
Virtual ~ Point ()
{
// Printf ("% p \ n", & Point ::~ Point );
Cout <"Point destructor" <endl;
}
Virtual void func_zzzy ()
{
Cout <"Point: func_zzzy" <endl;
Printf ("the address of this -- func_zzzy: % p \ n", & Point: func_zzzy );
}

Protected:
Float x, y, z;
};


Int main (int argc, char * argv [])
{
Point point;
Point: print ();
Point. printThis ();
Point. printVt ();
Point. callVtFuncs (5 );
Point. printVirtualFunAddress ();
Printf ("sizeof func: % u \ n", sizeof (& main ));
Printf ("% p \ n", & main );

Printf ("sizeof memfunc: % u \ n", sizeof (& Point: printVirtualFunAddress ));
Printf ("% p \ n", & Point: printVirtualFunAddress );

Printf ("% p \ n", & Point: func_zzzy );

Printf ("sizeof your memfunc: % u \ n", sizeof (& Point: func_zzzy ));
Cout <typeid (point). name () <endl;

Return 0;
}


The Point class includes four virtual functions.
The output result is as follows:

Point constructor
& Point: x = 0x4
& Point: y = 0x8
& Point: z = 0xc
& This-> x = 0xbffff624
& This-> y = 0xbffff628
& This-> z = 0xbffff62c
The address of object, this: 0xbffff620
The address of vt: 0x8048fc0


0x8048fc0
Point: callVtFuncs => address of this fun: 0x8048a12
Point: func_hs
The address of this -- func_hs: 0x1
0x8048fc4
Point: callVtFuncs => address of this fun: 0x8048a64
Point: func_functions
The address of this -- func_pointer: 0x5
0x8048fc8
Point: callVtFuncs => address of this fun: 0x8048c8e
0x8048fcc
Point: callVtFuncs => address of this fun: 0x8048cda
0x8048fd0
Point: callVtFuncs => address of this fun: 0x8048cf8
Point: func_zzzy
The address of this -- func_zzzy: 0x11


Func_hs: 0x1
Func_example :( nil)
Func_zzzy: 0x5
0x11
Sizeof func: 4
0x804880c
Sizeof memfunc: 8
0x8048bdc
0x11
Sizeof memory memfunc: 8

Data member is relatively simple and there is no big problem. This is mainly because the virtual table is complicated. The first small problem is
Sequence problems. Experiments show that the virtual function pointers in vtable are placed in the declared order. Regardless of virtual desctructor
In which location, there will be two slots, that is, two virtual desctructor. I am not sure why there are two slots,
It will be discussed later.
One of my first questions is about typeinfo. Remember Lippman in Inside the c ++ object model
In the object model mentioned above, the typeinfo is placed in the first slot of the vtable, and according to the above example, the first slot is declared
So where does typeinfo exist?

The first vtable address is 0x8048fc0, and the memory address starting from 0x8048fb0 is as follows:

(Gdb) x/16a 0x8048fb0
0x8048fb0: 0x75253a63 0xa 0x0 0x8048fdc <_ ZTI5Point>
0x8048fc0 <_ ZTV5Point + 8>: 0x8048a12 <Point: func_hs ()> 0x8048a64 <Point: func_prop ()> 0x8048c8e <Point ::~ Point ()> 0x8048cda <Point ::~ Point ()>
0x8048fd0 <_ ZTV5Point + 24>: 0x8048cf8 <Point: func_zzzy ()> 0x746e 0x804a4c8 <_ ZTVN10 _ cxxabiv117 _ class_type_infoE @ listen + 8>
0x8048fe0 <_ ZTI5Point + 4>: 0x8048fd4 <_ ZTS5Point> 0x3b031b01 0x98 0x12

We can see that there is information about the Point class before the vtable. The value at 0x8048fbc is 0x8048fdc <_ ZTI5Point>, and the value at 0x8048fdc is: 0x804a4c8 <_ ZTVN10 _ cxxabiv117 _ class_type_infoE @ CXXABI_1.3 + 8. You can guess this is related to the type.


In the output, I set a breakpoint on the line of typeid (point). After Entering the function, we can see that:

(Gdb) s
Std: type_info: name (this = 0x8048fdc)
At/usr/lib/gcc/i686-pc-linux-gnu/4.7.1/.../include/c ++/4.7.1/typeinfo: 102
102 {return _ name [0] = '*'? _ Name + 1: _ name ;}
(Gdb) n
5 Point

The type information of point is 5 Point, and the parameter information passed in by type_info: name Is 0x8048fdc.
-Fdump-class-hierarchy:


Vtable for Point
Point: _ ZTV5Point: 7u entries
0 (int (*) () 0
4 (int (*) (& _ ZTI5Point)
8 (int (*) () Point: func_hs
12 (int (*) () Point: func_functions
16 (int (*) () Point ::~ Point
20 (int (*) () Point ::~ Point
24 (int (*) () Point: func_zzzy

Class Point
Size = 16 align = 4
Base size = 16 base align = 4
Point (0xb60019a0) 0
Vptr = (& Point: _ ZTV5Point) + 8u)


The results are quite clear. In the implementation of g ++, the true typeinfo information is placed after the vtable, and its location is in the address before the vtable
The specified information. In the information about the Point class, the starting position is & Point: _ ZTV5Point, and its value is 0x0, followed
Information, and then the entry point of the vtable. That is, vptr = (& Point: _ ZTV5Point) + 8u ). This pointer of the point class is resolved after the type is converted
The referenced value is even though vptr. As for size = 16, it is easy to understand that one vptr + three float.


Another strange information is the point to member output. A single output is that three virtual functions are 0x1 0x5 0x11, respectively, while
The output information in printVirtualFunAddress is very strange, namely 0x1, nil, 0x5, which is why we need to add a test in the main function.
The reason for the pointer size of the function is that the common function is 4 bytes, and the member function is indeed 8 bytes, whether it is virtual function or not.
When a parameter is pushed to the stack, the result of the second push is treated as the value of the second parameter. So there will be the above results.

Finally, the two desctructor problems should be omitted when calling a function through the function pointer above. If you remove virtual,
Therefore, desctructor is not found in the vtable.
The following is the result of objdump: objdump-d a. out | grep PointD

8048932: e8 51 03 00 00 call 8048c88 <_ ZN5PointD1Ev>
8048944: e8 3f 03 00 00 call 8048c88 <_ ZN5PointD1Ev>
08048c88 <_ ZN5PointD1Ev>:
8048cc5: 74 0b je 8048cd2 <_ ZN5PointD1Ev + 0x4a>
08048cd4 <_ ZN5PointD0Ev>:
8048ce0: e8 a3 ff call 8048c88 <_ ZN5PointD1Ev>


In the two functions, main calls <_ ZN5PointD1Ev>, which is the virtual desctrucotr we declared above. In the memory layout,
The <_ ZN5PointD1Ev> is located before the vtable, And the <_ ZN5PointD0Ev> is located before <_ ZN5PointD0Ev>.

08048cd4 <_ ZN5PointD0Ev>:
8048cd4: 55 push % ebp
8048cd5: 89 e5 mov % esp, % ebp
8048cd7: 83 ec 18 sub $0x18, % esp
8048cda: 8b 45 08 mov 0x8 (% ebp), % eax
8048cdd: 89 04 24 mov % eax, (% esp)
8048ce0: e8 a3 ff call 8048c88 <_ ZN5PointD1Ev>
8048ce5: 8b 45 08 mov 0x8 (% ebp), % eax
8048ce8: 89 04 24 mov % eax, (% esp)
8048ceb: e8 80 f9 ff call 8048670 <_ ZdlPv @ plt>
8048cf0: c9 leave www.2cto.com

It seems that the <_ ZN5PointD1Ev> should also be called. This should be generated by the compiler, and I am not quite clear about it.

Author: Xicheng

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.