Virtual function and virtual function table in C ++

zhaozj2021-02-16  46

Comrade learning C I don't know if I have encountered such a confusion as I am: Is the virtual function in C achieved? In various inheritance relationships, what is the structure of the virtual function table? I used to be very important, but later in the process of using the ATL, I found not what I think. Everyone knows that the characteristics of the C language itself will be a very convenient thing to make COM programming, but you have to know what the virtual function table is in the end. Telling the book of C grammar is not obligated to tell you what kind of virtual function table generated by C , this is the headache. Since the test is a very happy thing, I am very willing to do this.

First write a function as the basis of our experiment. Pass in the virtual function table pointer to display the contents of the virtual table.

Void Dispvft (DWORD * PVFT) {Printf ("VFT POINTER:% P / N", PVFT); Printf ("Begin / N"); DWORD * P = (DWORD *) * PVFT; // Get the first address of VFT While (* p) file: // This place I am looking for whether it is empty to judge whether it is the end: // Most of the cases are right, but it is not allowed to {Printf ("vf:% p,% p / n ", p, * p); p ;} printf (" end / n / n ");}

First we look at the virtual function table when you look at a single class: Class C1 {public: C1 () {file: // printf ("in c1 / n"); file: // dispvft ((dword *) THIS);} Virtual f1 ()}}; void main () {C1 C1;

File: // Due to the non-member data in C1, all we can use this way to determine the number of virtual function table pointers in file: // c1, the number of printf ("Vftptr Count:% D / N", SizeOf (C1) / 4); file: // Display memory structure Dispvft ((DWORD *) & C1);

Output: VFTPTR Count: 1VFT Pointer: 0012FF7CBEGINVF: 0012FF7CBEGINVF: 00420048, 00401078 (C1 :: f1) end

Very simple, don't talk more, this is the result of our expectation.

Let's take a simple inheritance experiment

Class C2: Public C1 {Public: C2 () {Printf ("IN C1 / N"); Dispvft ((DWORD *) THIS);} Virtual F2 () {}

Void main () {C2; C1 * PC1 = & C2; Printf ("vftptr count:% d / n", sizeof (c2) / 4); Printf ("c1 / n"); DISPVFT ((DWORD *) PC1 ); Printf ("C2 / N"); Dispvft (DWORD *) & C2);} Output: in C1VFT Pointer: 0012FF7CBEGINVF: 00420048, 00401087 (C1 :: f1) end

IN C2VFT POINTER: 001200F7CBEGINVF: 004200F4, 00401087 (C1 :: F1) File: // The first item is the first site of the table and the corresponding entry content, see the address, different from the IN C1, indicating that it is different Two tables VF: 004200F8, 0040108C (C2 :: F2) end

vftptr count: 1C1VFT Pointer: 0012FF7CBeginVF: 004200F4, 00401087 (C1 :: F1) VF: 004200F8, 0040108C (C2 :: F2) EndC2VFT Pointer: 0012FF7CBeginVF: 004200F4, 00401087 (C1 :: F1) VF: 004200F8, 0040108C (C2: : F2) End

You can see that the last virtual function table pointer is still the same, and the c1 (base class) and the c2 (derived class) are in order in order.

Below is a multi-inheritance class c1 {public: C1 () {file: // printf ("in c1 / n"); file: // dispvft ((dword *) this);} Virtual F1 () {}}};

Class C2 {public: C2 () {file: // Printf ("in c1 / n"); file: // dispvft ((dword *) this);} Virtual F2 () {}}; Class C3: Public C1 , public c2 ​​{public: c3 () {file: // printf ("in c1 / n"); file: // dispvft ((dword *) this);} Virtual f3 () {}};

Void main () {C3; C2 * PC2 = & C3; C1 * PC1 = & C3; Printf ("Vftptr Count:% D / N", SizeOf (C3) / 4); Printf ("C1 / N"); DISPVFT ((DWORD *) PC1); Printf ("C2 / N"); DISPVFT ((DWORD *) PC2); Printf ("C3 / N"); Dispvft (DWORD *) & C3);} Output: vftptr count: 2C1VFT POINTER: 0012FF78BEGINVF: 00420104, 00401046 (C1 :: F1) VF: 00420108, 0040101E (C3 :: f3) end

C2VFT Pointer: 0012FF7CBEGINVF: 00420100, 00401028 (C2 :: F2) VF: 00420104, 00401046 (C1 :: F1) VF: 00420108, 0040101E (C3 :: f3) end

C3VFT POINTER: 0012FF78BEGINVF: 00420104, 00401046 (C1 :: F1) VF: 00420108, 0040101E (C3 :: f3) end

The virtual function table pointer becomes two, that is, it is now used to maintain a table with two virtual function table pointers, summarizing the number of virtual function table pointers equals the number of base classes. As for the number of virtual functions, it should be three. You can remove the code I added in the constructor to take a look at the output. You will find that the first address of each output is different, that is, of course, not the same table.

Let's talk about multiple layers: Class C1 {public: C1 () {Printf ("in c1 / n"); dispvft (dword *) this);} Virtual F1 () {}}};

Class C2: Public C1 {Public: C2 () {Printf ("IN C2 / N"); Dispvft (DWORD *) THIS);} Virtual F2 () {}}; Class C3: Public C2 {Public: C3 ( ) {Printf ("IN C3 / N"); DISPVFT (DWORD *) THIS);} Virtual F3 () {}};

Void main () {C3; C2 * PC2 = & C3; C1 * PC1 = & C3; Printf ("Vftptr Count:% D / N", SizeOf (C3) / 4); Printf ("C1 / N"); DISPVFT ((DWORD *) PC1); Printf ("C2 / N"); Dispvft (DWORD *) PC2); Printf ("C3 / N"); Dispvft (DWORD *) & C3);} Output: in C1VFT Pointer : 0012F7CBEGINVF: 00421090, 00401046 (C1 :: f1) end

In C2VFT Pointer: 0012FF7CBEGINVF: 0042010C, 00401046 (C1 :: f1) file: // Here is the vftable of class C2, the first output is its first site and entry content VF: 00420110, 00401028 (C2 :: f2) end

In C3VFT Pointer: 0012FF7CBEGINVF: 0012FF7CBEGINVF: 0042109C, 00401046 (C1 :: F1) VF: 004210A0, 00401028 (C2 :: F2) VF: 004210A4, 00401078 (C3 :: f3) end

VFTPTR Count: 1C1VFT Pointer: 0012FF7CBEGINVF: 0012FF7CBEGINVF: 0042109C, 00401046VF: 004210A0, 00401028VF: 004210A4, 00401078

C2VFT POINTER: 0012FF7CBEGINVF: 0042109C, 00401046VF: 004210A0, 00401028VF: 004210A4, 00401078END

C3VFT POINTER: 0012FF7CBEGINVF: 0042109C, 00401046VF: 004210A0, 00401028VF: 004210A4, 00401078END

Get the result: We see that the virtual function table pointer is one, but you look at the output of each constructor! The first item of the output is the first site of the table and the corresponding entry. Everyone can see that the first site is not the same. This shows that there are three different tables, then this class has three virtual functions. You may think, when is these three tables? C is wasting your space without the consent of you (multiple inheritance also exists). Microsoft wants to remove other unused virtual functions: __ declspec (novTable)

Class __Declspec (NOVTABLE) C1 {public: C1 () {file: // Printf ("in c1 / n"); file: // dispvft (dword *) this); file: // here to go, since there is no That table, how to output} Virtual f1 () {}}};

Class __Declspec (NOVTABLE) C2: Public C1 {public: C2 () {file: // printf ("in c2 / n"); file: // dispvft ((dword *) this); // This is to go, since No table, how to output} Virtual F2 () {}}; Class C3: Public C2 {public: C3 () {Printf ("IN C3 / N"); DISPVFT (DWORD *) THIS);} Virtual F3 ) {}};

Void main () {C3; C2 * PC2 = & C3; C1 * PC1 = & C3; Printf ("Vftptr Count:% D / N", SizeOf (C3) / 4); Printf ("C1 / N"); DISPVFT ((DWORD *) PC1); Printf ("C2 / N"); Dispvft (DWORD *) PC2); Printf ("C3 / N"); Dispvft (DWORD *) & C3);} Output: in C3VFT Pointer : 0012F7cBeginvf: 0042109C, 00401046VF: 004210A0, 00401028VF: 004210A4, 00401078END

VFTPTR Count: 1C1VFT Pointer: 0012FF7CBEGINVF: 0012FF7CBEGINVF: 0042109C, 00401046VF: 004210A0, 00401028VF: 004210A4, 00401078

C2VFT POINTER: 0012FF7CBEGINVF: 0042109C, 00401046VF: 004210A0, 00401028VF: 004210A4, 00401078END

C3VFT POINTER: 0012FF7CBEGINVF: 0042109C, 00401046VF: 004210A0, 00401028VF: 004210A4, 00401078END

You can see everything is normal, just don't know, your program is slimming, but if you decide to get the virtual function table that you want to go, you can determine that this class should be a base class, not the last derived. Class used. Otherwise, it may be wrong, such as:

Void Func1 (C1 * P) {p-> f1 ();} void main () {C2 C2; FUNC1 (& C2);

This situation will be wrong, there is no virtual function table, how can the virtual function call can be implemented?

If there is anything wrong, I hope that comrades refer to enlightenment.

转载请注明原文地址:https://www.9cbs.com/read-27052.html

New Post(0)