C + + Multiple inheritance of the next subclass and the parent-class pointer conversion bug

Source: Internet
Author: User

These two days, a C + + novice asked me a question, his project has a piece of code execution is not correct, do not know what the reason. I made a tune, and if the code is streamlined, it's probably the following:

classibasea{ Public:    Virtual voidFnA () =0; intM_ntesta;};classibaseb{ Public:    Virtual voidFnB () =0; intM_ntestb;};classCTest: PublicIbasea, Publicibaseb{ Public:    Virtual voidFnA () {printf ("fna\n"); }    Virtual voidFnB () {printf ("fnb\n"); }};int_tmain (intARGC, _tchar*argv[]) {CTest*ptest =NewCTest; void*p = (void*) PTest; Ibasea*pbasea = (ibasea*) p; Pbasea-FnA (); Ibaseb*pbaseb = (ibaseb*) p; Pbaseb-FnB (); Pbaseb= (ibaseb*) PTest; Pbaseb-FnB ();    GetChar (); return 0;}

Perhaps the reader will find it strange that there is a void* conversion in the middle. This is not surprising, because this code is I put the most fundamental problem in his code after streamlining, because the combination of his code context framework design, in the middle is really so, just a glance seems easy to ignore. In fact, just a simple debugging will find that the pointer variable Pbaseb in fact and Pbasea is exactly the same, and debugging found its virtual table address is the same, but if the writing is not the same.
Pbaseb = (ibaseb*) pTest;

So how did this difference come about? This is going to start with a pointer conversion from C + + multiple inheritance.

In fact, C + + internal pointer conversion is a common thing, such as unsigned number to signed number conversion, C + + typical will report a warning, if it is set to the highest level or even direct error. Sub-class pointers to the parent class pointer, because C + + multiple inheritance use of the occasion is not too much, so most of the time the direct conversion can be, even according to the above conversion method is not a problem. Because C + + pointer conversion is simply the original object's address according to the new type to parse it.

However, this simple conversion has a little-known pit for multiple inheritance of C + +. For the above code, the object memory layout generated by the CTest class might look like this:

Ibasea----------- >

_vfptr

M_ntesta

Ibaseb----------- >

_vfptr

M_ntestb

If it is converted to Ibasea, then directly ptest the memory address of the first address, in accordance with Ibasea resolution can be, so say Pbasea->fna ();

But for ibaseb *pbaseb = (ibaseb*) p, in fact, Ptest's memory header address is parsed directly according to Ibasea. From the memory layout, the first one is mistaken for the IBASEB address. Instead of executing PBASEB->FNB (), this statement actually takes the first function address in the virtual table and calls it directly. Since two virtual function definitions are consistent, there is no problem, otherwise it will collapse directly.

From disassembly we can also see that the entire execution process is to directly assign p to Pbaseb, and then take the first 4 bytes of Pbaseb, that is, the virtual table address, and then take the virtual table address of the first 4 bytes, that is, the address of a virtual function. Then, starting from the 008114DB address, pass in the this pointer, save the virtual function address to EAX and then call.

    Ibaseb *pbaseb = (ibaseb*) p;008114ce  mov         eax,dword ptr [p]  008114d1  mov         dword ptr [PBASEB], EAX      pbaseb, FnB () 008114d4  mov         eax,dword ptr [pbaseb]  008114d7  mov         edx, DWORD ptr [EAX]  008114d9  mov         esi,esp  008114DB  mov         ecx,dword ptr [Pbaseb]  008114DE  mov         eax,dword ptr [edx]  008114E0  call        eax  008114E2  cmp         ESI,ESP  008114E4  Call        @ILT+

From here we can clearly see how the results are going.

If the correct conversion method is used, what does the execution process look like? As a matter of fact, we all know and know that the IBASEB pointer is actually shifted to the correct position. Combined with anti-Assembly look;

    Pbaseb = (ibaseb*) ptest;008114e9  cmp         dword ptr [PTest],0  008114ED  JE          WMAin+0ADh (8114FDh)  008114EF  mov         eax,dword ptr [pTest]  008114f2  add         eax,  8  008114f5  mov         dword ptr [EBP-100h],eax  008114FB  jmp         wmain+0b7h (811507h)  008114FD  mov         dword ptr [EBP-100h],0  00811507  mov         ecx,dword ptr [ebp-100h]  0081150D  mov         

OK, now the process is clear, in the end, there is a EAX plus 8 operation, the address is directly offset to the correct position.

The above problem word, is the multiple inheritance, must not first convert the this pointer to other types, and then converted to the parent class pointer. As if there is an object delete, make sure that the pointer is the original type and do the delete, otherwise the destructor may not be called and the memory leaks.

C + + Multiple inheritance of the next subclass and the parent-class pointer conversion bug

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.