Problem with C ++ Multiple I / O Addressing

Please ignore the #include parts if they are made correctly. Also, this may be implementation specific (but also the concept of vtables), but I'm just curious as it improves me for visualizing multiple inheritance. (By the way, I'm using MinGW 4.4.0)

initial code:

class A { public: A() : a(0) {} int a; }; //Edit: adding this definition instead void f(void* ptrA) { std::cout<<((A*)ptrA)->a; } //end of editing of original posted code #if 0 //this was originally posted. Edited and replaced by the above f() definition void f(A* ptrA) { std::cout<<ptrA->a; } #endif 

This compiled and generated object code.

in another compiler that I use (after including the header file for the above code):

 class C : public B , public A { public: int c; }objC; f(&objC); // ################## Label 1 

memory model for objC:

 //<1> stuff from B //<2> stuff from B //<3> stuff from A : int a //<4> stuff from C : int c 

&objC will contain the start address <1> in the memory model adopted above as / when will the compiler move it to <3>? Does this happen during call verification in Label 1 ?

EDIT ::

since Lable 1 seems to give a return by simply making it a little more obscure to the compiler. Pls see the edited code above. Now when does the compiler do and where?

+3
source share
2 answers

Short answer: the compiler will adjust the values ​​of the pointer during cast operations if it knows the relationship between the base and derived classes.

Let's say the address of your instance of an object of class C was at address 100. And let sayofof (C) == 4. Like sizeof (B) and sizeof (A).

When a throw occurs, for example:

 C c; A* pA = &c; // implicit cast, preferred for upcasting A* pA = (A*)&c; // explicit cast old style A* pA = static_cast<A*>(&c); // static-cast, even better 

The pointer value pA will be the memory address c plus the offset from where "A" begins with C. In this case, pA will refer to the memory address 104 if sizeof (B) is also 4.

All this is true for passing a pointer to a derived class into a function that expects a pointer to a base class. Implicit casting will occur in the same way as pointer offset adjustment.

Similarly, for downcasting:

 C* pC = (C*)(&a); 

The compiler will take care of setting the pointer value during setup.

The one who β€œreceived” all this when the class is declared ahead without a full declaration:

  // foo.h class A; // same as above, base class for C class C; // same as above, derived class from A and B inline void foo(C* pC) { A* pA = (A*)pC; // oops, compiler doesn't know that C derives from A. It won't adjust the pointer value during assigment SomeOtherFunction(pA); // bug! Function expecting A* parameter is getting garbage } 

This is a real mistake!

My general rule. Avoid the old "C-style" and prefer using the static_cast operator or just rely on implicit casting without an operator to do the right thing (to enhance). The compiler will throw an error if the casting is invalid.

+1
source

Yes, you are absolutly right.

To fully understand the situation, you must know what the compiler knows at two points:

  • In Label 1 (as you already defined)
  • Inner function f ()

    (1) The compiler knows the exact binary layout of both C and A and how to convert from C * to * and will do this on the call site (Label 1)

    (2) The internal function f (), however, the compiler only (should) know (s) about A * and therefore is limited to members of A (int a in this case) and cannot be confused about whether a particular instance is part of something either still or not.

+1
source

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


All Articles