Catalog
1. Overview
2. Preparatory knowledge points before starting
- 2.1 Do you know what different types of pointers mean?
- 2.2c file is compiled into a target file. What does the target file contain?
3.c++ Static Polymorphism
- 3.1 Actual coding operation
- 3.2 Implementation Principle
- 3.3 Understanding from the Perspective of c
4.c++ Dynamic Polymorphism
- 4.1 Actual coding operation
- 4.2 Implementation Principle
- 4.3 Understanding from the Perspective of c
5. Compile and run environment
- 5.1 Operating System
- 5.2 Compiler
1. Overview
c + + is a hybrid programming language, which supports both object-oriented and process-oriented, and mainly object-oriented. Among the three characteristics of c + +: inheritance, encapsulation and polymorphism, polymorphism is the most difficult to understand. This paper will interpret the polymorphism of c + + from the perspective of c +.
2. Preparatory knowledge points before starting
2.1 Do you know what different types of pointers mean?
Different pointer types mean different ways of resolving the same memory start address. Here's a chestnut.
- Code test4.c
#include <stdint.h> #include <string.h> #include <malloc.h> #include <stdio.h> int32_t g_int = 10; int main() { //Request 5 byte heap memory void * p = malloc(5); //The value of each byte is set to 90 memset(p, 90, 5); //Declare a char pointer pc to the starting address of the allocated memory char * pc = (char *)p; //Declare an int32_t pointer pint to the starting address of the allocated memory int32_t * pint = (int32_t *)p; //Take a byte of memory from the starting address to parse it into char variables if (*pc == 90) { printf("char yes\n"); } //Take four bytes of memory from the start address to resolve to the int32_t variable if (*pint == 90 + (90 << 8) + (90 << 16) + (90 << 24)) { printf("int yes\n"); } return 0; }
- Operation results
- Detailed illustration
2.2c file is compiled into a target file. What does the target file contain?
- At least include function symbols, global variables (if global variables are defined in the file).
- From the gcc and nm commands, we can see that test4.o generated by the test code above contains a global variable g_int, a defined function symbol main, three undefined function symbols malloc, memset, put.
- Command execution results
3. c++ Static Polymorphism
3.1 Actual coding operation
- Code test5.cpp
#include <iostream> using namespace std; void fun1() { cout << "fun1 call" << endl; } void fun1(int a) { cout << "fun1 a call" << endl; } int main() { fun1(); fun1(10); return 0; }
- Operation results
3.2 Principle of Implementation
- Through the characteristics of overload, it is decided to call that function at the compilation stage, so it is called static polymorphism.
- C + + compiler will re-sign function symbols when compiling code (c compiler will not). When C + + compiler encounters overload calls, it directly calls the re-signed function. When we use the nm command to view the symbols of executable files, we can see two re-signed symbols.
3.3 Understanding from the Perspective of c
#include <stdio.h> void _Z4fun1v() { printf("fun1 call\n"); } void _Z4fun1i(int a) { printf("fun1 a call\n"); } int main() { _Z4fun1v(); //Corresponding to void fun1(); _Z4fun1i(10); //Corresponding to the previous void fun1(int a); return 0; }
4.c++ Dynamic Polymorphism
4.1 Actual coding operation
- Code test6.cpp
#include <iostream> using namespace std; class Base { public: virtual void sleep() { cout << "Base sleep" << endl; } virtual void eat() { cout << "Base eat" << endl; } virtual void run() { cout << "Base run" << endl; } }; class Animal : public Base { public: size_t age; void sleep() { cout << "Animal sleep" << endl; } void eat() { cout << "Animal eat" << endl; } void run() { cout << "Animal run" << endl; } }; /* Define a function pointer type, which is void () (Animal *); Used to point to virtual functions sleep, eat, run; The reason why there is an additional Animal* parameter here is because of the non-static member functions of the c++ class. By default, the compiler adds parameters to the class pointer at the beginning of the parameter list */ typedef void (* pFun)(Animal * animal); int main() { Animal dargon; Animal dog; Base * pBase = &dargon; Base & pRe = dog; //Dynamic polymorphism is achieved by pointing the base class pointer to the derived class object pBase->sleep(); //Dynamic polymorphism is achieved by referencing a base class to a derived class object pRe.sleep(); /* Remove the virtual table pointer for Animal. (size_t *)&dargon -> dargon Start address translated to size_t* *(size_t *)&dargon -> dargon The starting address starts with sizeof(size_t) bytes parsed into size_t (virtual table pointer value) (size_t *)*(size_t *)&dargon -> Convert this value to size_t*type ps: size_t The size of the pointer variable is the same as that of size_t, which is 4 bytes on the 32-bit computer and 8 bytes on the 64-bit computer. */ size_t * vptable_dargon = (size_t *)*(size_t *)&dargon; size_t * vptable_dog = (size_t *)*(size_t *)&dog; cout << "size_t size = " << sizeof(size_t) << endl; //A class shares a virtual table pointer if (vptable_dog == vptable_dargon) { cout << "vptable value is equal" << endl; } //Traversal virtual table pointer while (*vptable_dargon) { //Take out each virtual table function pFun fun = (pFun)(*vptable_dargon); //Call each virtual table function fun(&dargon); vptable_dargon++; } return 0; }
- Operation results
4.2 Implementation Principle
- It is realized by the override feature of c++. Only at runtime can we know what function is actually called, so it is called dynamic polymorphism.
- c + + adds a virtual function table (static variables of the class) to each class with virtual functions, and inserts a virtual table pointer to it at the starting address of each class object, through which runtime polymorphism can be achieved.
4.3 Understanding from the Perspective of c
- Code test7.cpp
#include <stdio.h> #include <malloc.h> #include <string.h> //Global static virtual table pointer, simulation class static virtual table pointer static size_t * pBaseVptable = NULL; static size_t * pAnimalVptable = NULL; struct Base { size_t * vptable; //Analog virtual table pointer }; struct Animal { struct Base base; //Simulated Animal Inheritance Base size_t age; }; typedef void (* pFun)(Base * pBase); void baseSleep(Base * pBase) { printf("Base sleep\n"); } void baseEat(Base * pBase) { printf("Base eat\n"); } void baseRun(Base * pBase) { printf("Base run\n"); } void animalSleep(Animal * pAnimal) { printf("Animal age[%d] sleep\n", pAnimal->age); } void animalEat(Animal * pAnimal) { printf("Animal age[%d] eat\n", pAnimal->age); } void animalRun(Animal * pAnimal) { printf("Animal age[%d] run\n", pAnimal->age); } //Base structure initialization void baseInit(Base * pBase) { pBase->vptable = pBaseVptable; } //Initialization of Animal Structures void AnimalInit(Animal * pAnimal) { pAnimal->base.vptable = pAnimalVptable; } /* Virtual table pointer initialization */ void vptableInit() { pBaseVptable = (size_t *)malloc(sizeof(size_t) * 4); pAnimalVptable = (size_t *)malloc(sizeof(size_t) * 4); memset(pBaseVptable, 0x0, sizeof(size_t) * 4); memset(pAnimalVptable, 0x0, sizeof(size_t) * 4); //Base class global virtual table initialization pBaseVptable[0] = (size_t)&baseSleep; pBaseVptable[1] = (size_t)&baseEat; pBaseVptable[2] = (size_t)&baseRun; //Animal class global virtual table initialization pAnimalVptable[0] = (size_t)&animalSleep; pAnimalVptable[1] = (size_t)&animalEat; pAnimalVptable[2] = (size_t)&animalRun; } void callVirtualFun(Base * pBase, int index) { pFun fun = (pFun)pBase->vptable[index]; fun(pBase); } int main() { //Virtual table initialization vptableInit(); Base * pBase = NULL; Animal * pAnimal = (Animal *)malloc(sizeof(Animal)); //Simulated Object Initialization AnimalInit(pAnimal); pAnimal->age = 99; //Analog base class pointer to derived class pBase = (Base *)pAnimal; //Simulated call virtual function callVirtualFun(pBase, 0); callVirtualFun(pBase, 1); callVirtualFun(pBase, 2); return 0; }
- Operation results
5. Compile and run environment
-
operating system
[root@iZ940zytujjZ ~]# uname -m -s
Linux x86_64 -
Compiler
[root@iZ940zytujjZ ~]# gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
[root@iZ940zytujjZ ~]# g++ --version
g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)