catalogue
Normal inheritance (excluding virtual functions)
Normal inheritance (including virtual function)
Virtual inheritance (excluding virtual functions)
Virtual inheritance (including virtual functions)
First, define several concepts:
Abstract class: classes containing pure virtual functions are called abstract classes. Abstract classes cannot instantiate objects, but can define pointers or reference variables. In actual development, we generally design base classes as abstract classes;
Virtual base class: the class inherited by virtual is called virtual base class, that is, the virtual keyword is added before the inheritance method;
virtual application scenario:
- Modify the member method, indicating that the method is a virtual function. The class containing the virtual function will automatically add a virtual function pointer (vfptr) member data, and vfptr points to the virtual function table (vftable).
- Modify the inheritance method, such as class B: virtual public A, which means virtual inheritance. At this time, A becomes A virtual base class; Then, when we generate an object with B, A virtual base class pointer (vbptr) will be automatically added to the memory layout of the object, and vbptr points to the virtual base class table (vbtable).
Four cases (memory layout for derived class objects)
Normal inheritance (excluding virtual functions)
#include<iostream> using namespace std; class A { public: void show() {cout << ma << endl;} private: int ma; }; class B : public A { public: void show() {cout << mb << endl;} private: int mb; }; int main() { cout << sizeof(A) << endl; // 4 cout << sizeof(B) << endl; // 8 return 0; }
Under the condition of ordinary inheritance (no virtual function), the derived class object memory layout stores the member variables of the base class first, and then the derived class's own member variables, as shown in the following figure:
Normal inheritance (including virtual function)
#include<iostream> using namespace std; class A { public: virtual void show() {cout << ma << endl;} private: int ma; }; class B : public A { public: void show() {cout << mb << endl;} private: int mb; }; int main() { cout << sizeof(A) << endl; // 16 memory alignment cout << sizeof(B) << endl; // 16 return 0; }
Under the condition of this common inheritance (including virtual functions), since the base class has virtual functions, the base class has virtual function pointers; the derived class overrides the virtual functions of the base class. At this time, the method is also a virtual function in the derived class, so the derived class also has virtual function pointers, which can be observed from sizeof() (Note: class and struct have memory alignment problems.) therefore, in the memory layout of derived class objects, first store a virtual function pointer, then store the member variables inherited from the base class, and finally store the member variables of the derived class itself. The memory layout is shown in the following figure:
Virtual inheritance (excluding virtual functions)
#include<iostream> using namespace std; class A { public: void show() {cout << ma << endl;} private: int ma; }; class B : virtual public A { public: void show() {cout << mb << endl;} private: int mb; }; int main() { cout << sizeof(A) << endl; // 4 cout << sizeof(B) << endl; // 16 return 0; }
In this virtual inheritance environment (the base class has no virtual function), because the derived class adopts virtual inheritance, a virtual base class pointer will be generated in the derived class, pointing to the virtual base class table (vbptr - > vbtable) through sizeof () we can also see that in this case, the memory layout of the derived class will first store vbptr, then store its own member variables, and finally store the member variables of the base class, as shown in the following figure:
Virtual inheritance (including virtual functions)
#include<iostream> using namespace std; class A { public: virtual void show() {cout << ma << endl;} private: int ma; }; class B : virtual public A { public: void show() {cout << mb << endl;} private: int mb; }; int main() { cout << sizeof(A) << endl; // 16 cout << sizeof(B) << endl; // 32 return 0; }
In this case, virtual inheritance and the base class has virtual functions. We can see from the output that the size of class B is 32; In the object memory layout of class B, first store the virtual base class pointer (accounting for 8 bytes), and then store B's own member variable MB (accounting for 4 bytes). Due to memory alignment, it is necessary to supplement 4 bytes, and then store the member variable inherited from the base class, First, the virtual function pointer (vfptr, accounting for 8 bytes), then ma (accounting for 4 bytes), and then the memory alignment is supplemented by 4 bytes, so the total is 8 + 4 + 4 + 8 + 4 + 4 = 32 bytes, as shown in the following figure: