Advertisement

why compiler stuff these things into the executable ?

Started by February 22, 2001 09:04 AM
4 comments, last by ed9er 23 years, 11 months ago
I use VC6+SP4 the simple situation:
  
class Base {};
class Child : virtual public Base {};
void main() {Child c;}
  
in VC's watch window i got these : sizeof(Base) 1 // i know this, compiler need a address sizeof(Child) 4 // not VPTR for VTABLE, here's no virutal method. &c 0012ff7c 0012ff7c 0043101c // suppose to be a pointer, so i go: 0043101c blah~~~~ // confused here comes the complicated situation:
  
class Base {};
class Child1 : virtual public Base {};
class Child2 : virtual public Base {};
class Final : public Child1, public Child2 {};
void main() {Final f;}
  
now is : sizeof(Base) 1 sizeof(Child1) 4 sizeof(Child2) 4 sizeof(Final) 8 &f 0x0012ff78 0012ff78 28 20 42 00 1C 20 42 00 // only 8 bytes are useful 0042201c 00 00 00 00 04 00 00 00 00 00 00 00 00422028 00 00 00 00 08 00 00 00 00 00 00 00 ok, by now i know that the first DWORD of f must be some kind pointer like VPTR, it point to a group of pointer which each point to a DWORD array which contains 3 elements and the second item seems like a offset value. my question is, when and why the executable will use these fields? why ask this? as for multiple inheritance, to avoid ambiguous when we call a function which occurs in both base class, we need to give the namespace qualifier, such as Child1::f() or Child2::f(); and another thing, the "virtual" keyword used for "eliminate the dup-subobject". but both of the two are all accomplished at compile-time, so the question arised : when and why the executable will use these fields? i read ISO-Spec/Book by BjornStr./Book by Eckel/...., no result, so i come here and post this... any tips should be appreciated! Edited by - ed9er on February 22, 2001 10:14:23 AM
------------------------------------------------------CCP is fascistic, they even banned www.sourceforge.net
I don''t know why you got what you got. When you use a virtual base class the class gets a pointer to an instance of the base class as opposed to getting the actual data members from the base as in normal inheritance. That is the only way the compiler can get both to use the same instance of the base. Both have a pointer to base and both pointers point to the same place. Why yours didn''t point to the same place I have no idea. I also have no idea why size of final doesn''t include the size of base.

As for when it is used it is used in a call to an inherited function. If you called a function in child1 then the function has to receive a pointer to this. That data at the address pointed to by this has to look exactly like an instance of child1. If the data members from base where merged into child1 as it would in inheritance then what followed would be the data members child1 added. This would create a problem when you called a function in child2 since this would not point to something that looked like an instance of child2 unless a duplicate copy of base was included in final. If it was duplicated then each time child1 changed the data in base then the data in the copy for child2 would have to also be changed. The same would be true for child2. Instead both expect a pointer to base followed by their own data members. So final has an instance of child1, followed by an instance of child2, followed by the data members of final. When a function in child1 is called then the this pointer for that function points to final and when child2 is called it points to final + sizeof(child1). When a function in base is called this is the value at the start of final.
Keys to success: Ability, ambition and opportunity.
Advertisement
thanks for the detailed reply!

i dunno if i get the point but i got these things in my mind :
1. this is a compiler-dependent issue
2. i''ll never use "virtual inheritance" unless i meet a "diamond" hierarchy diagram, since it''s actually the same whether use "virtual" or not when there''s no "diamond", from a user''s view, not compiler''s
3. still a problem, do you mean that the members should be placed look like this :

Base(hided instance)
-------------- addr_1
members
-------------- end

Final
-------------- addr_2
addr_1
Child1 members
Child2 members
Final members
--------------

the this of Base : addr_1, no doubt
the this of Final: addr_2, (base-pointer is *this)
for Child1 : addr_2, (base-pointer is *this)
for Child2 : addr_2 + sizeof(pointer) + sizeof(Child1)
(base-pointer is *(this-sizof(pointer)-sizeof(Child1))

assume that the compiler just know how to find the base-pointer, but how the Child2''s member function could know the "this" is a transformation of Final or just a directly pointer of Child2, for latter case, the base-pointer is *this ..... confused

anyway, many thanks again
------------------------------------------------------CCP is fascistic, they even banned www.sourceforge.net
No, there is another addr_1 between child1 members and child2 members in final. This on a call to child1 would point to the first addr_1, but to the second addr_1 on a call to child2.
Keys to success: Ability, ambition and opportunity.
aha, it''s make sense, thx!
is there any offical specification about this? can you give me some url or book''s name? not mistrust, just need more detail
------------------------------------------------------CCP is fascistic, they even banned www.sourceforge.net
I don''t know of any, but that doesn''t mean there are not any. If you put some actual data in your instance then you can more easily see what is where. Just add something like an integer to each and give each a constructor that sets the values to differant values. You can also set up some code to change the values and verify that they are where you think they are.
Keys to success: Ability, ambition and opportunity.

This topic is closed to new replies.

Advertisement