C++ basic this pointer and another 'polymorphism'

  • 2020-04-02 01:22:54
  • OfStack

A, introducing
Define an object of a class, first the system has allocated space to the object, and then the constructor is called.

A class has multiple objects, and when a function of an object is called in a program, it is possible to access the member variables of that object.
For each object of the same class, the same class function is Shared. Objects have separate variables, but no separate functions, so when a function is called, the system must let the function know which object's operation it is, in order to determine which object's member variables belong to.
The object used to distinguish between member variables and objects is called this pointer. It is in fact the address of the object, as you can see from the disassembled code.

Second, the analysis
1. Test code:


/////////////////////////////////////////////////////////////////////////////////////
#include<iostream>
using   namespace   std;
/////////////////////////////////////////////////////
class A
{
public:
    A(char *szname)
    {
        cout<<"construct"<<endl;
        name
 = new char[20];
        strcpy(name,
 szname);
    }
    ~A()
    {
        cout<<"destruct"<<endl;
        delete name;
    }
    void    show();
private:
    char    *name;
};
/////////////////////////////////////////////////////
void    A::show()
{
    cout<<"name
 = "<<name<<endl;
}
/////////////////////////////////////////////////////
int main()
{
    A
 a("zhangsan");
    a.show();
    system("pause");
    return 0;
}

The program is compiled and run on VC++6.0 32-bit operating system.
The compiled EXE file, disassembly. The disassembler tool is OllyDbg.

2. Disassembly analysis
The screenshot of the key points is as follows:
(1) it can be seen from figure 1 that this pointer is passed to the member function through the ECX register. This pointer is the address of the object.

The < img style = "border = 0 border - BOTTOM: 0 px; BORDER - LEFT: 0 px; PADDING - BOTTOM: 0 px; MARGIN: 0 px; PADDING - LEFT: 0 px; PADDING - RIGHT: 0 px; BORDER - TOP: 0 px; BORDER - RIGHT: 0 px; PADDING - TOP: 0 px "Alt =" "SRC =" / / files.jb51.net/file_images/article/201307/201307260846592.jpg ">

Figure 1. The Main function

(2) it can be found from figure 2 that the member variable accessing the object USES the this pointer passed in through ECX before.

  The < img style = "border = 0 border - BOTTOM: 0 px; BORDER - LEFT: 0 px; PADDING - BOTTOM: 0 px; MARGIN: 0 px; PADDING - LEFT: 0 px; PADDING - RIGHT: 0 px; BORDER - TOP: 0 px; BORDER - RIGHT: 0 px; PADDING - TOP: 0 px "Alt =" "SRC =" / / files.jb51.net/file_images/article/201307/201307260846593.jpg ">

Figure 2 the show () function

3. In-depth understanding

From the screenshot and related information, it is clear that the ECX before the constructor and show() function are called is this pointer, that is to say, this is a verification experiment, the answer is clear, all we need to do is to experience it. However, if I don't know C++ and I don't know anything about this pointer, I can still find this thing called "this pointer". Through the dynamic debugging of OD, when the name is displayed, it can be found that the source of the name is ECX. OD reloads to see where the ECX came from before entering the show() function. Eventually, step by step, the ECX is an address, and the first value in the address is also an address, pointing to a string. If you go up to the constructor above show(), you can see that there's a new operation, a strcpy operation, and you can see where the string space, where the content comes from. At this point, the analysis is basically done.

Through this process, you can discover a lot of knowledge of C++. Such as: The space of the object is allocated before the constructor is called ; There are no functions in the object ; This pointer is passed through register ECX; Objects defined by declaration have their space allocated on the stack ; And so on the knowledge relating to system or c + +.

However, for a person who does not know C++, the above paragraph of experience is not. Assembly instructions do not see the C++ idea, this pointer is just an address; Objects are just Spaces; Constructors, destructors, and other functions are nothing more than a collection of instructions.

Multiple objects defined by the same class in C++ look like this from the assembly instruction: there are many block address Spaces, they have the same size. When different objects call member functions, in the assembler instruction, they all call the same address. This call instruction is actually a JMP instruction, which is used to jump to a certain location. Before the call instruction, an address is usually put into the ECX, of course, sometimes using the stack or other registers.

C++ inheritance, polymorphism, encapsulation, to the assembly programmer is nothing magical, For C++ programmers That's different. It saves a lot of work. It turns a lot of things over to the compiler Let the compiler do it for you.

The objects discussed by C++ programmers and their many features and advantages eventually become "low-level" instructions, and possibly inefficient instructions, but even so, the advantages far outweigh the disadvantages, making programming easy and efficient.

Four, extension

Suddenly thought of C++ polymorphic, a sentence "subclass type of pointer to the parent type of pointer", polymorphic is achieved through virtual functions. The principle of virtual function and its related content, detailed understanding is not detailed.

For my simple understanding, there is A base class A and subclasses B and C, and there is A function that takes A pointer to the base class A as an argument, and then calls A member function of the base class through the pointer inside the function. If the called base class member function is not a virtual function, then it is impossible to achieve polymorphism, because when translated into assembly instructions, the member function is called at this place is a call instruction, and then the call instruction jumps to some place to execute, which is a fixed address. By defining it as a virtual function, the member function is called in this place through the virtual function table pointer to determine which function to call, and the virtual function table pointer is placed in the address space of the object, if the object changes, then the virtual function table pointer also changes, the function to call is different. For A function that takes A pointer to base class A as an argument, the pointer is the address of the object. If the address passed is the address of an object of subclass B or C, then the virtual function table pointer is different and the member function is called differently.

This is called polymorphism, which makes it possible to call the same function differently by passing different arguments, which can be base class objects or many different subclass objects. They differ from class to class.

The memory layout of objects with virtual functions has one more pointer to the virtual function table than objects without virtual functions. Because virtual functions are called through virtual function table Pointers, there is polymorphism.

Consider also C++ 's this pointer, a member function in a class that distinguishes objects based on this pointer According to this pointer Implements member variables that access different objects.

Is this also a manifestation of polymorphism? The polymorphic here is no longer the "superclass pointer to subclass objects" doctrine, but embodied in Different objects of the same class Between, Call the same member function , according to the parameter "this pointer" to achieve access to different objects of the member variables. Member functions access member variables in Compilation time cannot be determined Which address of the member variable is it accessing The runtime determines the address of the access based on this pointer . This is very similar to the polymorphism of classes: the virtual member function of a base class is called in a function that takes a pointer to the base class as an argument, the object of which class is called cannot be determined at compile time when the program is running, and the object of which class is not determined until run time.

This pointer identifies different objects of the same class. In other words, this pointer enables member functions to access different objects of the same class. Further, the this pointer causes the member function to access different member variables depending on the this pointer. This is polymorphism, but it is inevitably exist polymorphism, the polymorphism with the base class and derived class is the polymorphism between different levels of polymorphism, it is not like common polymorphism can choose by the choice of using virtual functions, it is a class corresponding to multiple objects, multiple objects sharing code brings the inevitable result of a member function.


Related articles: