Why can I call some class member functions correctly through NULL pointer?

Source: Internet
Author: User

Original article: http://blog.csdn.net/starlee/article/details/2062586

There is a simple class below:

Class cnullpointcall
{
Public:
Static void test1 ();
Void Test2 ();
Void test3 (INT itest );
Void test4 ();

PRIVATE:
Static int m_istatic;
Int m_itest;
};

Int cnullpointcall: m_istatic = 0;

Void cnullpointcall: test1 ()
{
Cout <m_istatic <Endl;
}

Void cnullpointcall: Test2 ()
{
Cout <"very cool! "<Endl;
}

Void cnullpointcall: test3 (INT itest)
{
Cout <itest <Endl;
}

Void cnullpointcall: test4 ()
{
Cout <m_itest <Endl;
}

Are the following codes correct? What will be output?

Cnullpointcall * pnull = NULL; // yes, it is to assign a null value to the pointer.
Pnull-> test1 (); // call 1
Pnull-> Test2 (); // call 2
Pnull-> test3 (13); // call 3
Pnull-> test4 (); // call 4

You must be wondering why I asked this question. How can a null pointer be used to call a class member function ?! However, this is surprising: Except for the call 4 line of code, the call of the other three class member functions is successful and the results can be correctly output, the program that contains the three lines of code can run very well.
After careful comparison, we can find the essential difference between the call 4 line code and the other three lines of code: This pointer is used in the member functions of the cnullpointcall class.
For a class member function, not an object corresponds to a separate member function body, but all such objects share this member function body. After the program is compiled, the member function address is determined. This pointer is used to differentiate the data of various objects of this type. All accesses to class data members in the function body will be converted to this-> data member mode.
The this pointer of an object is not part of the object and does not affect the result of sizeof ("object. This scope is within the class. When a non-static member of the struct class in the non-static member function of the class, the compiler automatically transmits the address of the object to the function as an implicit parameter. That is to say, even if you do not write the this pointer, the compiler also adds this during compilation. It serves as an implicit parameter of non-static member functions and accesses to all Members are carried out through this.
For the above example, the value of this is the value of pnull. That is to say, the value of this is null. While test1 () is a static function, the compiler will not pass this pointer to it, so the line of call 1 code can be called correctly (this is equivalent to cnullpointcall: test1 (); For Test2 () and test3 (). Although the compiler will pass the this pointer to these two functions, they do not use the this pointer to invoke member variables of the class, therefore, the call 2 and call 3 lines of code can be called correctly. For the member function test4 (), you need to use the this pointer for the member variable of the callback class, in this case, if the value of this pointer is null, the program will crash.
In fact, we can imagine that the compiler converts test4 () into the following form:

Void cnullpointcall: test4 (cnullpointcall * This)
{
Cout <this-> m_itest <Endl;
}

The line of call 4 code is converted into the following form:

Cnullpointcall: test4 (pnull );

Therefore, the program crashes when m_itest is accessed through this pointer.
Next, let's look at the compilation Code Compiled with VC 2005 to explain in detail the magic this pointer.
The compilation code generated by C ++ code above is in the following form:

Cnullpointcall * pnull = NULL;
0041171e mov dword ptr [pnull], 0
Pnull-> test1 ();
00411725 call cnullpointcall: test1 (411069 H)
Pnull-> Test2 ();
0041172a mov ECx, dword ptr [pnull]
0041172d call cnullpointcall: Test2 (4111e0h)
Pnull-> test3 (13 );
00411732 push 0dh
00411734 mov ECx, dword ptr [pnull]
00411737 call cnullpointcall: test3 (41105ah)
Pnull-> test4 ();
0041173c mov ECx, dword ptr [pnull]
0041173f call cnullpointcall: test4 (411032 H)

By comparing the assembly code generated by the static function test1 () and the other three non-static function calls, we can see that: before a non-static function is called, the pointer pnull (that is, this pointer) pointing to the object is put into the ECX register (mov ECx, dword ptr [pnull]). This is the special feature of the this pointer. You can see the difference between the this pointer and the common function parameters in the C ++ code assembly code of call 3: The common function parameters are directly pushed to the stack (push 0dh ), this pointer is put into the ECX register. If you want to use a class member variable in a non-member function of the class, you can access the ECX register to obtain the this pointer to the object, then, the corresponding member variables are found by adding the offset of the member variables to this pointer.
The following example illustrates how the this pointer is passed to the member function and how to use this to access member variables.
It is still a very simple class:

Class ctest
{
Public:
Void setvalue ();

PRIVATE:
Int m_ivalue1;
Int m_ivalue2;
};

Void ctest: setvalue ()
{
M_ivalue1 = 13;
M_ivalue2 = 13;
}

Use the following code to call a member function:

Ctest test;
Test. setvalue ();

The assembly code of the above C ++ code is:

Ctest test;
Test. setvalue ();
004117dc Lea ECx, [test]
004117df call ctest: setvalue (4111cch)

Similarly, put the pointer to the object in the ECX register, and then call the member function setvalue () of the ctest class (). The address 4111cch is actually a jump command, which is transferred to the member function setvalue.

004111cc JMP ctest: setvalue (411750 H)

The 411750h is the address of setvalue (), a member function of the ctest class.

Void ctest: setvalue ()
{
00411750 push EBP
00411751 mov EBP, ESP
00411753 sub ESP, 0cch
00411759 push EBX
0041175a push ESI
0041175b push EDI
0041175c push ECx // 1
0041175d Lea EDI, [ebp-0CCh]
00411763 mov ECx, 33 H
00411768 mov eax, 0 cccccccch
0041176d rep STOs dword ptr es: [EDI]
0041176f pop ECx // 2
00411770 mov dword ptr [ebp-8], ECx // 3
M_ivalue1 = 13;
00411773 mov eax, dword ptr [this] // 4
00411776 mov dword ptr [eax], 0dh // 5
M_ivalue2 = 13;
0041177c mov eax, dword ptr [this] // 6
0041177f mov dword ptr [eax + 4], 0dh // 7
}
00411786 pop EDI
00411787 pop ESI
00411788 pop EBX
00411789 mov ESP, EBP
0041178b pop EBP
0041178c RET

The following is an analysis of the key lines in the above assembly code:
1. Press the value in the ECX register to the stack, that is, press this pointer to the stack.
2. The ECX register outputs the stack, that is, the this pointer outputs the stack.
3. Put the value of ECx in the specified place, that is, the this pointer in [ebp-8.
4. Put the value of this pointer into the eax register. At this point, the this pointer points to the test object. The test object only has two int-type member variables and is stored continuously in the test object memory. That is to say, the this pointer currently points to m_ivalue1.
5. assign a value of 0dh (hexadecimal 13) to the address pointed to by the register eax ). In fact, it is to assign 13 values to the member variable m_ivalue1.
6. Same as 4.
7. Add a value of 4 to the address pointed to by the register eax. As described in section 4, the memory of the eax register is placed with the this pointer, And the this pointer points to the member variable m_ivalue1 of the continuously stored int type. This pointer is added with 4 (sizeof (INT), that is, the address of the member variable m_ivalue2. Therefore, this row assigns values to the member variable m_ivalue2.
Through the above analysis, we can understand the implementation method of this pointer in C ++ from the bottom layer. Although different compilers use different processing methods, the C ++ compiler must comply with the c ++ standard, so the implementation of this pointer should be similar.

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.