C++ 虚拟继承是如何通过c+在内存中实现的+;编译程序?
我被虚拟关键词弄糊涂了。我试图找出编译器是如何在内存中实现这一点的。 好的,让我举例说明。我使用MicrosoftVisualStudio2010作为虚拟依赖编译器的实现 这是第一个代码C++ 虚拟继承是如何通过c+在内存中实现的+;编译程序?,c++,visual-c++,c++11,C++,Visual C++,C++11,我被虚拟关键词弄糊涂了。我试图找出编译器是如何在内存中实现这一点的。 好的,让我举例说明。我使用MicrosoftVisualStudio2010作为虚拟依赖编译器的实现 这是第一个代码 #include<iostream> class one { int _a; public: virtual ~one(){} }; class two:public one { int _a; public: virtual ~two(){} }; int mai
#include<iostream>
class one
{
int _a;
public:
virtual ~one(){}
};
class two:public one
{
int _a;
public:
virtual ~two(){}
};
int main()
{
using namespace std;
cout<<"sizeof two="<<sizeof(two)<<endl;
return 0;
}
#包括
一班
{
国际组织;
公众:
虚拟~one(){}
};
第二类:公共一级
{
国际组织;
公众:
虚拟~two(){}
};
int main()
{
使用名称空间std;
cout这包含了您需要了解的所有内容,虚拟继承是如何由编译器的编写者在VC++中实现的
下面是第三类
构造函数的反汇编
00A516BD cmp dword ptr [ebp+8],0
00A516C1 je three::three+60h (0A516F0h)
00A516C3 mov eax,dword ptr [this]
00A516C6 mov dword ptr [eax],offset three::`vbtable' (0A57828h) => 4 Bytes
00A516CC mov ecx,dword ptr [this]
00A516CF add ecx,8
00A516D2 call one::one (0A51253h)
00A516D7 or dword ptr [ebp-0D4h],1
00A516DE mov ecx,dword ptr [this]
00A516E1 add ecx,10h
00A516E4 call two::two (0A512BCh)
00A516E9 or dword ptr [ebp-0D4h],2
00A516F0 mov eax,dword ptr [this]
00A516F3 mov ecx,dword ptr [eax]
00A516F5 mov edx,dword ptr [ecx+4]
00A516F8 mov eax,dword ptr [this]
00A516FB mov dword ptr [eax+edx],offset three::`vftable' (0A57820h) => 4 Bytes
00A51702 mov eax,dword ptr [this]
00A51705 mov ecx,dword ptr [eax]
00A51707 mov edx,dword ptr [ecx+8]
00A5170A mov eax,dword ptr [this]
00A5170D mov dword ptr [eax+edx],offset three::`vftable' (0A57814h) => 4 Bytes
00A51714 mov eax,dword ptr [this]
00A51717 pop edi
00A51718 pop esi
00A51719 pop ebx
00A5171A add esp,0D8h
如上所示,
虚拟基表指针占用4个字节,(vbtable)
2虚拟函数表指针取4*2=8字节,(vftable)
成员one::_a
需要4个字节
成员two::_a
需要4个字节
因此,在所有20个字节中。
pdf(第17页)中给出了2个虚拟函数表指针的原因,如下所示:
Visual C++中,为了避免在获取VFTABLE条目时对虚拟基础P的昂贵转换,T的新虚函数,在新的VFTABLE中接收新的VFPTR,在T.< P>的顶部引入,这完全是具体实现的,编译器可以自由地按其喜欢的方式组织事物。(并使生成的类任意大小)提供所有功能
从外观上看,我假设类three
包含三个隐藏指针(系统上每4个字节):一个“虚拟基指针”,包含三个
中虚拟基的地址,一个虚拟函数指针包含一个中虚拟函数的地址,第二个虚拟函数指针包含两个中虚拟函数的地址
指针是3*4字节,加上基类的两个int
成员是2*4字节,总共是20字节
当然,如果要在64位机器上编译此代码(使用8字节指针),然后你会得到一些不同的结果:至少32字节,但如果编译器决定需要填充
int
成员,可能会更多。我认为,你应该在答案中添加一些段落,以防删除此pdf。事实上,只链接的答案是不受欢迎的,因为它们倾向于链接腐烂。这很好,而且实际上我鼓励您提供参考资料来补充您的答案;但是,答案的内容应该在堆栈溢出时立即可以访问(如果仅以宽泛的笔划)。如果您解释为什么20…@51k很高兴知道pdf回答了它,请稍候,我在第11页:)!!“正如您在上面看到的”-这应该会很有帮助“正如你在上面清楚看到的"注意:您的虚拟基类示例…很奇怪。理论上,虚拟继承用于解决菱形问题:D继承自C和B,C和B都继承自A。您没有菱形,因此虚拟继承在您的情况下是无用的。@MatthieuM。您的观点与matt相关,但我并没有试图实现我刚刚学习的任何内容:)当你学习时,你应该学习所有方面!!!这也是我所怀疑的,但为什么要使用两个虚拟函数指针??
00A516BD cmp dword ptr [ebp+8],0
00A516C1 je three::three+60h (0A516F0h)
00A516C3 mov eax,dword ptr [this]
00A516C6 mov dword ptr [eax],offset three::`vbtable' (0A57828h) => 4 Bytes
00A516CC mov ecx,dword ptr [this]
00A516CF add ecx,8
00A516D2 call one::one (0A51253h)
00A516D7 or dword ptr [ebp-0D4h],1
00A516DE mov ecx,dword ptr [this]
00A516E1 add ecx,10h
00A516E4 call two::two (0A512BCh)
00A516E9 or dword ptr [ebp-0D4h],2
00A516F0 mov eax,dword ptr [this]
00A516F3 mov ecx,dword ptr [eax]
00A516F5 mov edx,dword ptr [ecx+4]
00A516F8 mov eax,dword ptr [this]
00A516FB mov dword ptr [eax+edx],offset three::`vftable' (0A57820h) => 4 Bytes
00A51702 mov eax,dword ptr [this]
00A51705 mov ecx,dword ptr [eax]
00A51707 mov edx,dword ptr [ecx+8]
00A5170A mov eax,dword ptr [this]
00A5170D mov dword ptr [eax+edx],offset three::`vftable' (0A57814h) => 4 Bytes
00A51714 mov eax,dword ptr [this]
00A51717 pop edi
00A51718 pop esi
00A51719 pop ebx
00A5171A add esp,0D8h