Why are pA, pB, pC not equal?

Consider the following program

#include<iostream> using namespace std; class ClassA { public: virtual ~ClassA(){}; virtual void FunctionA(){}; }; class ClassB { public: virtual void FunctionB(){}; }; class ClassC : public ClassA,public ClassB { }; void main() { ClassC aObject; ClassA* pA = &aObject; ClassB* pB = &aObject; ClassC* pC = &aObject; cout<<"pA = "<<pA<<endl; cout<<"pB = "<<pB<<endl; cout<<"pC = "<<pC<<endl; } 

pA, pB, pC should be equal, but the result

pA = 0031FD90

pB = 0031FD94

pC = 0031FD90

why pB = pA + 4? and when i change

 class ClassA { public: virtual ~ClassA(){}; virtual void FunctionA(){}; }; class ClassB { public: virtual void FunctionB(){}; }; 

to

 class ClassA { }; class ClassB { }; 

result

pA = 0030FAA3

pB = 0030FAA4

pC = 0030FAA3

pB = pA + 1?

+6
source share
3 answers

A multiplied inherited object has two combined sub-objects. I would suggest that the compiler points to one of the pointers to an internal object.

+1
source

C has two inherited subobjects, so it is a concatenation of object A and object B. When you have object C, it consists of object A, followed by object B. They are not located at the same address, therefore. All three pointers point to the same object, but as different superclasses. The compiler does the shift for you, so you don't need to worry about it.

Now. Why is there a difference of 4 in one case and 1 in another? Well, in the first case, you have virtual functions for A and B, so each subobject must have a pointer to its own vtable (a table containing the addresses of allowed calls to virtual functions). So in this case, sizeof(A) is 4. In the second case, you have no virtual functions, so there is no vtable. But each subobject must be addressable independently, so the compiler still has to allocate different addresses for the class A subobject and class B subobject. The minimum difference between the two addresses is 1. But I wonder if EBO (empty base class optimization) is in this case shouldn't have been sailing.

0
source

This is a compiler implementation detail. The reason you fall into this case is because there is MI in your code.

Think about how a computer accesses a member in ClassB using an offset to access a member. So, let's say you have two ints in class B, using the following statement to access the second member of int.

  *((int*)pb + 1) // this actually will be assembly generate by compiler 

But if pb points to the beginning of aObject in your class, this will no longer work, so the compiler needs to create several versions of the assembly to access the same base of elements in the class’s inheritance structure and have time consuming.

This is why the compiler sets pb to not equal pa, which the above code will do, this is the easiest and most efficient way to implement it.

And that also explains why pa == pc , but not equal to pb .

0
source

Source: https://habr.com/ru/post/956132/


All Articles