Typecasting with virtual features

In the code below pC == pA:

class A { }; class B : public A { public: int i; }; class C : public B { public: char c; }; int main() { C* pC = new C; A* pA = (A*)pC; return 0; } 

But when I add a pure virtual function to B and implement it in C, pA! = PC:

 class A { }; class B : public A { public: int i; virtual void Func() = 0; }; class C : public B { public: char c; void Func() {} }; int main() { C* pC = new C; A* pA = (A*)pC; return 0; } 

Why is pA not equal to pC in this case? Don't they both point to the same ā€œCā€ in memory?

+7
source share
3 answers

You see a different value for your pointer, because the new virtual function causes the vtable pointer to be injected into your object. VC ++ places the vtable pointer at the beginning of the object (which is typical, but a purely internal detail).

Add a new field to A to make it easier to explain.

 class A { public: int a; }; // other classes unchanged 

Now in memory, your pA and A look something like this:

 pA --> | a | 0x0000004 

Once you add B and C to the mix, you get the following:

 pC --> | vtable | 0x0000000 pA --> | a | 0x0000004 | i | 0x0000008 | c | 0x000000C 

As you can see, pA points to the data after vtable, because it knows nothing about vtable or how to use it, or even that it is. pC knows about vtable, so it points directly to the table, which simplifies its use.

+6
source

A pointer to an object is convertible to a pointer to a base object and vice versa, but the conversion should not be trivial. It is quite possible and often necessary that the base pointer have a different meaning than the derived pointer. That's why you have a strong system and conversions. If all the pointers were the same, you wouldn't need it either.

+3
source

Here are my assumptions based on the question.

1) You have a case where you drop from C to and get the expected behavior.
2) You added a virtual function, and this action no longer works (while you can no longer retrieve data from A immediately after transferring to A, you get data that does not make sense to you).

If these assumptions are true, then the difficulties you are encountering are inserting a virtual table in B. This means that the data in the class is no longer aligned with the data in the base class (as bytes are added to the class, the virtual table is hidden from you ) A fun test would be to check the sizeof to see the growth of unknown bytes.

To solve this problem, you should not use direct access from A to C to collect data. You must add a getter function that is in and inherited from B and C.

Given your update in the comments, I think you should read this , it explains the virtual tables and memory layout, and how this compiler is dependent. This link explains in more detail what I explained above, but gives examples of pointers that are different values. Actually, I had WHY you asked the question incorrectly, but it looks like you still need the information. At the same time, the virtual table at this point is taken into account from C (note C-8 is 4, which, in my opinion, will be the size of the address required for the virtual table on a 32-bit system).

0
source

All Articles