"Polymorphism" is a key and core feature of C ++, and "dynamic binding technology" is the most important technology for C ++ compilers! Welcome to the C ++ experts to give me a rough understanding.

Source: Internet
Author: User

Some of my superficial understandings are as follows:

A program uses CPU commands to operate and operate data resources in the memory, that is, to change the binary number of the memory.

In the memory, binary data, commands, data, and memory units pointed to by the PC instruction counter are commands.

Data is a command, and instructions are data. Therefore, you only need 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.

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 (the hfile is included) and forming code with correct logic and syntax.

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

It is finally translated into assembly code or machine code.

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)

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:

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. The relative address. After adding the address, the operating system will re-adjust it.


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-> 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 look for 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 (),

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 ()

}

}

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.