用virtual继承以后多出来那些究竟是什么鬼东西啊?

ed9er 2001-02-22 05:29:00
sizeof增加了4字节,按地址找过去,发现看不懂,然后用菱形的样式做了个继承,

class Base {
public :
char p[0x100];
};

class Child1 : virtual public Base {};

class Child2 : virtual public Base {};

class MI : public Child1, public Child2 {};

void main() {
Base b; Child1 c1; Child2 c2; MI mi;
}
然后再跑,sizeof() : mi is 0x108 bytes,c1,c2 is 0x104 bytes, b is 0x100 bytes,看头,c1、c2都多了一个指针,mi多了两个,四个指针的值连续排列,间隔是0x0c bytes :

c1 : 0047201c
c2 : 00472028
mi : 00472034
00472040

0047201C 00 00 00 00 04 00 00 00 00 00 00 00 ............
00472028 00 00 00 00 04 00 00 00 00 00 00 00 ............
00472034 00 00 00 00 04 00 00 00 00 00 00 00 ............
00472040 00 00 00 00 08 00 00 00 00 00 00 00 ............

请问这些东西有什么用?因为virtual继承对子对象的重叠放置和成员函数调用的确定(假设没有virtual方法)是编译时就已经完成了的,跟这个应该没有关系,这个东西有点象vtable,但含义搞不懂,中间那个DWORD好象是个偏移量,其他的呢?是不是reserved了的?
...全文
220 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
cber 2001-02-26
  • 打赏
  • 举报
回复
回复始祖鸟,我的Inside C++ Object Model是公司里的纸版的,候捷译的。我也想D/L到原文呢
cber 2001-02-25
  • 打赏
  • 举报
回复
For virtual inheritance, compiler will add another table to record the base classes' information, more likely to the vtable. From Lipp96, <<Inside C++ Object Modle>>.
yoci 2001-02-25
  • 打赏
  • 举报
回复
这个问题我也问过,经人指点读了msdn中的一篇文章,一切ok。虚继承是个很麻烦的东西,它的实现随编译器的不同而不同,下面是VC的实现方法
msdn ::Technical Articles/Visual Tools/Visual C++ 6.0/C++: Under the Hood
有例有图,通俗易懂,好文章啊!

你也可以看看当时讨论的情况:
http://www.csdn.net/expert/TopicView.asp?id=49354
ed9er 2001-02-25
  • 打赏
  • 举报
回复
哈哈,这个libudywizer给我的完全错了,虽然行的通,但实在太拙劣,还是MSDN里面说的那种实现漂亮
ed9er 2001-02-25
  • 打赏
  • 举报
回复
非常感谢,请问cber哪里可以当到那本书?yoci,那个帖子我看了,太长,看的不是很仔细,感觉里面也有一些不懂装懂的,msdn的马上去看,这里是在另外一个BBS上别人的解释,听起来很有道理,而且我又是一惯不信任VC调试器的,所以……,转贴过来,感兴趣的可以浏览一下,分马上给

ed9er Member since: 2/8/2001 From:
Posted - 22 February 2001 10:04:29 AM
I use VC6+SP4

the simple situation:


class Base {};
class Child : virtual public Base {};
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 {};
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




LilBudyWizer Member since: 12/17/1999
Posted - 23 February 2001 3:32:51 AM
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.




ed9er Member since: 2/8/2001 From:
Posted - 23 February 2001 4:41:50 AM
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




LilBudyWizer Member since: 12/17/1999
Posted - 23 February 2001 7:26:54 AM
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.



ed9er Member since: 2/8/2001 From:
Posted - 23 February 2001 9:15:48 AM
aha, it 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




LilBudyWizer Member since: 12/17/1999
Posted - 24 February 2001 11:18:04 PM
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.



zzroom 2001-02-24
  • 打赏
  • 举报
回复
我也想知道
tuabo 2001-02-22
  • 打赏
  • 举报
回复
以我的理解,因该是指向父类指针,就像定义虚函数一样,

不求甚解,还请各位专家指点。

69,380

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧