In-depth analysis: Implementation of C ++ "polymorphism" in the Compiler

Source: Internet
Author: User

Author: feijj2002

Theory

The following content is my personal understanding. Share it with you. correct the error.

The program uses the CPU command (the CPU command is the binary stream that the CPU can recognize, and the CPU can send various current pulses to control other electronic circuits ), operations on data resources in the memory, that is, changes the binary number of the memory, and also changes the level.

In the memory, binary data is used. Which is a command and data?

The memory unit pointed to by the PC instruction counter is the instruction.

Where the PC points, which is the command, so the data is also the command, the command is also the data, the program only needs to manage the PC register.

At the language level, a program is composed of functions and data. Function calling actually changes the Pc value and address transfer.

There are two types of data:

One is to allocate address space during compilation, such as global data.

One is to allocate address space, such as local data, by the stack top pointer maintained by the compiler and the offset relative to the stack top pointer at runtime.

(The other is dynamically allocated in the heap)

Certificate -------------------------------------------------------------------------------------------------------------------------------------

A vc project consists of many H and CPP files,

The compiler is responsible for collecting all the identifiers or symbols that appear in the CPP file (H files are included in CPP) and forming binary code (OBJ files) with correct logic and syntax)

The connector is responsible for determining and adjusting the relative address of the function, and ensuring that each function call (that is, address transfer) in CPP is valid. Each address that accesses memory data is, is valid.

Finally, the connector is translated into assembly code or machine code. (DLL and exe executable files)

To collect identifiers and symbols, the compiler maintains a symbol ing table with three columns (or three fields ):
1. Type column (variable type or function type, which is filled by the compiler during compilation)
2. Name column (variable or function name, which is filled by the compiler during compilation)
3. The address bar (which is a relative address. The offset value is placed in this column of the member variable type. After loading, It is adjusted by the operating system, that is, address relocation. During connection, filled by connectors)

Certificate -------------------------------------------------------------------------------------------------------------------------------------

Practical Application

Each time a variable or member function is declared, the compiler generates a ing element.

For example:

Int;

Class

{

Int M_a;

Int m_ B;

Void fun1 ();

}

The two generated ing table records are:



Name Bar | type bar | Address Bar ()

A | int | point to the Declaration definition of A, relative address. After loading, the operating system re-adjusts it.

A: M_a | int | offset address 0. Actual address during running: This + 0

A: m_ B | int | offset address 4. Actual address during running: This + 4

A: fun1 | A: fun1 | point to the: fun1 () definition, relative address, after being planted, it will be adjusted by the operating system.

For compiler dynamic binding technology, see the following:

Class
{

Public:
Virtual fun1 ();

Virtual fun6 ();

Void fun2 ();

/*

When the virtual keyword is displayed, the compiler creates a virtual table for this class.

Index | function pointer

0 | point to a: fun1 () Definition

1 | point to a: fun6 () Definition

When the member function declaration appears, the compiler fills in the ing table

Name Bar | type bar | Address Bar

A: fun2 () | A: fun2 | (filled by the connector) points to a: fun2 () Definition

*/
}

// B inherits from

Class B: public

{

Public:
Virtual fun1 ();

Void fun3 ();

/*

Virtual function fun1 ():

Redefine, create a virtual table, and inherit the virtual table items of the parent class,

Modified the pointer of the first item ("A: fun1 () function") in the virtual table to point to the User-Defined Function B: fun1 ().

Index | function pointer

0 | point to B: fun1 () Definition (redefinition)

1 | point to a: fun6 () Definition (no redefinition)

When the member function fun3 () declaration is displayed, add a column in the ing table:

Name Bar | type bar | Address Bar

B: fun3 () | B: fun3 | point to B: fun3 () Definition

Member function fun2 inherited from the parent class ()

Add a column to the ing table: records the fun2 () function inherited from.

Name Bar | type bar | Address Bar

B: fun2 () | A: fun2 | point to the parent class A: fun2 () Definition

*/
}

// C inherits from
Class C: public

{

Public:
Virtual fun6 ();

Void fun4 ();

/*

Virtual function fun1 ():

Redefine, create a virtual table, and inherit the virtual table items of the parent class,

Modified the pointer of the second item ("A: fun6 () function") in the virtual table to point to the self-defined C: fun6 () function.

Index | function pointer

0 | point to a: fun1 () Definition

1 | point to C: fun6 () Definition (rewrite)

If the member function fun4 () is displayed, add a column in the ing table:

Name Bar | type bar | Address Bar

C: fun4 () | C: fun4 | point to the C: fun4 () Definition

Member function fun2 inherited from the parent class ()

Add a column to the ing table: records the fun2 () function inherited from.

Name Bar | type bar | Address Bar

C: fun2 () | A: fun2 | point to the parent class A: fun2 () Definition

*/

}

Call
Main ()
{
B var1;
C var2;
A * P;
 
P = & var1;
 

Var1.fun2 ();

/*

Var1.fun2 () call, static binding:

When compiling here, the compiler finds the name column in The ing table and finds the B: fun2 () name (because var1 is of the B type). The corresponding type column is "function type, the type is named A: fun2 (because this function is defined by type A). The pointer value in the address bar is "point to a: fun2 ()". Therefore, here, the function call is replaced by the "steering: pointer value in the address bar" by the compiler. It can be understood that the value of the instruction counter is changed to "pointer value in the address bar"

*/

*/

P-> fun2 ();

/*

P-> fun2 (), static binding: This is easy to understand. during compilation, the name is "A: fun2 ()" (because P is of the type)

*/

P-> fun2 (), static binding: This is easy to understand. during compilation, the name is "A: fun2 ()" (because P is of the type)

*/

P-> fun2 (), static binding: This is easy to understand. during compilation, the name is "A: fun2 ()" (because P is of the type)

*/

P-> fun2 (), static binding: This is easy to understand. during compilation, the name is "A: fun2 ()" (because P is of the type)

*/

P-> fun2 (), static binding: This is easy to understand. during compilation, the name is "A: fun2 ()" (because P is of the type)

*/

P-> fun3 ();

/*

P-> fun3 (), This call may cause a compilation error, because type A does not declare and define the fun3 () function, and the name of a: fun3 () cannot be found, only B: fun3 () Name

*/

P-> fun1 ();

/*
P-> fun1 (); fun1 () is a virtual function. Similarly, when compiled here, does the compiler also find the name "A: fun1 ()" in the ing table? No.
Because the name A: fun1 () is not found in the ing table, because the keyword "virtual" exists before the name declaration of fun1 ",
During class declaration and definition, the compiler maintains a global data structure "virtual table" for each class with the virtual keyword"

Virtual table:

1. Index; 2. Function pointer (this value changes accordingly after the subclass overrides the virtual function)

Therefore, when the compiler finds that a "virtual function" is called,
The compiler has done the following:

Replace P-> fun1 () with: p-> vptr [offset],

Vptr name: virtual table pointer:
Maintained by the compiler (as mentioned above), every class containing virtual functions generates objects. In the memory, the first four bytes are vptr, and the value is static, all objects of the same type have the same vptr value and point to the same virtual table;

The offset value varies with the Declaration Order of the virtual function. If the first statement is used, the index is 0, the first statement appears in the virtual table, and the second statement is 1... (If the offset is 0, it is P-> vptr [0].)

P is the base class and can point to any object of the subclass.

(Additional:

1. Actually, the type conversion is: Memory cutting, and the memory under the jurisdiction is reduced from large to small. In the real world, it is allowed. In C ++, it is also allowed; the compiler does not allow conversion from a base class object to a subclass object. As a result, memory access may be out of bounds.

2. The pointer type actually determines the memory range that can be accessed through this pointer

),

The type of the object to be pointed to varies with vptr.
Therefore, p-> vptr [0], the function call address value cannot be determined during compilation, mainly because
The object pointed to by the P pointer cannot be determined (does P point to B or C? Or other..., but the offset can be determined)
Therefore, the vptr value cannot be determined,
Until the program runs, the address of the function called by P-> vptr [0] depends on the object type pointed to by P.
If P points to the B subclass, P points to the vptr of the first 4 bytes in the memory to the virtual table of B, and the first pointer of the virtual table points to the address defined by the function.
If P points to the C subclass, then ....
This method can be used to determine the function call address until running, that is, "dynamic binding "*/

P-> fun6 ();

/*

As mentioned above, function fun6 () is not required for Class B rewriting. Therefore, the compiler will actually call class A: fun6 () and perform the following operations:

P-> fun6 () is changed to P-> vptr [1]. Because fun6 is the second declaration, offset is 1.

*/

P = & var2;
P-> fun1 (); // dynamic binding, same as above, call a: fun1 ()
P-> fun2 (); // static, same as above

P-> fun6 (); // call C: fun6 ()
P-> fun4 ();
// Compilation error. Because fun4 () is not a virtual function, the compiler cannot find the: fun4 () name in the ing table,
// Unless forced conversion: (C *) P)-> fun4 (),}

Virtual table:

1. Index; 2. Function pointer (this value changes accordingly after the subclass overrides the virtual function)

Therefore, when the compiler finds that a "virtual function" is called,
The compiler has done the following:

Replace P-> fun1 () with: p-> vptr [offset],

Vptr name: virtual table pointer:
Maintained by the compiler (as mentioned above), every class containing virtual functions generates objects. In the memory, the first four bytes are vptr, and the value is static, all objects of the same type have the same vptr value and point to the same virtual table;

The offset value varies with the Declaration Order of the virtual function. If the first statement is used, the index is 0, the first statement appears in the virtual table, and the second statement is 1... (If the offset is 0, it is P-> vptr [0].)

P is the base class and can point to any object of the subclass.

(Additional:

1. Actually, the type conversion is: Memory cutting, and the memory under the jurisdiction is reduced from large to small. In the real world, it is allowed. In C ++, it is also allowed; the compiler does not allow conversion from a base class object to a subclass object. As a result, memory access may be out of bounds.

2. The pointer type actually determines the memory range that can be accessed through this pointer

),

The type of the object to be pointed to varies with vptr.
Therefore, p-> vptr [0], the function call address value cannot be determined during compilation, mainly because
The object pointed to by the P pointer cannot be determined (does P point to B or C? Or other..., but the offset can be determined)
Therefore, the vptr value cannot be determined,
Until the program runs, the address of the function called by P-> vptr [0] depends on the object type pointed to by P.
If P points to the B subclass, P points to the vptr of the first 4 bytes in the memory to the virtual table of B, and the first pointer of the virtual table points to the address defined by the function.
If P points to the C subclass, then ....
This method can be used to determine the function call address until running, that is, "dynamic binding "*/

P-> fun6 ();

/*

As mentioned above, function fun6 () is not required for Class B rewriting. Therefore, the compiler will actually call class A: fun6 () and perform the following operations:

P-> fun6 () is changed to P-> vptr [1]. Because fun6 is the second declaration, offset is 1.

*/

P = & var2;
P-> fun1 (); // dynamic binding, same as above, call a: fun1 ()
P-> fun2 (); // static, same as above

P-> fun6 (); // call C: fun6 ()
P-> fun4 ();
// Compilation error. Because fun4 () is not a virtual function, the compiler cannot find the: fun4 () name in the ing table,
// Unless forced conversion: (C *) P)-> fun4 (),}

Virtual table:

1. Index; 2. Function pointer (this value changes accordingly after the subclass overrides the virtual function)

Therefore, when the compiler finds that a "virtual function" is called,
The compiler has done the following:

Replace P-> fun1 () with: p-> vptr [offset],

Vptr name: virtual table pointer:
Maintained by the compiler (as mentioned above), every class containing virtual functions generates objects. In the memory, the first four bytes are vptr, and the value is static, all objects of the same type have the same vptr value and point to the same virtual table;

The offset value varies with the Declaration Order of the virtual function. If the first statement is used, the index is 0, the first statement appears in the virtual table, and the second statement is 1... (If the offset is 0, it is P-> vptr [0].)

P is the base class and can point to any object of the subclass.

(Additional:

1. Actually, the type conversion is: Memory cutting, and the memory under the jurisdiction is reduced from large to small. In the real world, it is allowed. In C ++, it is also allowed; the compiler does not allow conversion from a base class object to a subclass object. As a result, memory access may be out of bounds.

2. The pointer type actually determines the memory range that can be accessed through this pointer

),

The type of the object to be pointed to varies with vptr.
Therefore, p-> vptr [0], the function call address value cannot be determined during compilation, mainly because
The object pointed to by the P pointer cannot be determined (does P point to B or C? Or other..., but the offset can be determined)
Therefore, the vptr value cannot be determined,
Until the program runs, the address of the function called by P-> vptr [0] depends on the object type pointed to by P.
If P points to the B subclass, P points to the vptr of the first 4 bytes in the memory to the virtual table of B, and the first pointer of the virtual table points to the address defined by the function.
If P points to the C subclass, then ....
This method can be used to determine the function call address until running, that is, "dynamic binding "*/

P-> fun6 ();

/*

As mentioned above, function fun6 () is not required for Class B rewriting. Therefore, the compiler will actually call class A: fun6 () and perform the following operations:

P-> fun6 () is changed to P-> vptr [1]. Because fun6 is the second declaration, offset is 1.

*/

P = & var2;
P-> fun1 (); // dynamic binding, same as above, call a: fun1 ()
P-> fun2 (); // static, same as above

P-> fun6 (); // call C: fun6 ()
P-> fun4 ();
// Compilation error. Because fun4 () is not a virtual function, the compiler cannot find the: fun4 () name in the ing table,
// Unless forced conversion: (C *) P)-> fun4 (),}

Virtual table:

1. Index; 2. Function pointer (this value changes accordingly after the subclass overrides the virtual function)

Therefore, when the compiler finds that a "virtual function" is called,
The compiler has done the following:

Replace P-> fun1 () with: p-> vptr [offset],

Vptr name: virtual table pointer:
Maintained by the compiler (as mentioned above), every class containing virtual functions generates objects. In the memory, the first four bytes are vptr, and the value is static, all objects of the same type have the same vptr value and point to the same virtual table;

The offset value varies with the Declaration Order of the virtual function. If the first statement is used, the index is 0, the first statement appears in the virtual table, and the second statement is 1... (If the offset is 0, it is P-> vptr [0].)

P is the base class and can point to any object of the subclass.

(Additional:

1. Actually, the type conversion is: Memory cutting, and the memory under the jurisdiction is reduced from large to small. In the real world, it is allowed. In C ++, it is also allowed; the compiler does not allow conversion from a base class object to a subclass object. As a result, memory access may be out of bounds.

2. The pointer type actually determines the memory range that can be accessed through this pointer

),

The type of the object to be pointed to varies with vptr.
Therefore, p-> vptr [0], the function call address value cannot be determined during compilation, mainly because
The object pointed to by the P pointer cannot be determined (does P point to B or C? Or other..., but the offset can be determined)
Therefore, the vptr value cannot be determined,
Until the program runs, the address of the function called by P-> vptr [0] depends on the object type pointed to by P.
If P points to the B subclass, P points to the vptr of the first 4 bytes in the memory to the virtual table of B, and the first pointer of the virtual table points to the address defined by the function.
If P points to the C subclass, then ....
This method can be used to determine the function call address until running, that is, "dynamic binding "*/

P-> fun6 ();

/*

As mentioned above, function fun6 () is not required for Class B rewriting. Therefore, the compiler will actually call class A: fun6 () and perform the following operations:

P-> fun6 () is changed to P-> vptr [1]. Because fun6 is the second declaration, offset is 1.

*/

P = & var2;
P-> fun1 (); // dynamic binding, same as above, call a: fun1 ()
P-> fun2 (); // static, same as above

P-> fun6 (); // call C: fun6 ()
P-> fun4 ();
// Compilation error. Because fun4 () is not a virtual function, the compiler cannot find the: fun4 () name in the ing table,
// Unless forced conversion: (C *) P)-> fun4 (),}

Comment:

What should I say? This is my understanding.
1. The program is static and the process modifies data.
2. The CPU extracts commands in the fetch period, not the memory units pointed to by the PC instruction counter. Although this sentence is good, it is not accurate. Haha
3. Data is data, and commands are commands. Generally, commands and data in the system are both stored in the memory. Some system data and commands are stored separately, including command memory and data storage.
4. The CPU extracts data from the memory and stores the data in the instruction register through the instruction counter. Then, it decodes the data through the decoder, generates control signals, operates ALU, and writes the data back to the memory.
5. Program data is stored in data segments (BSS), stacks, and stacks.

Related Article

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.