我当时正在阅读关于虚拟继承的维基百科文章。我看了整篇文章,但我真的跟不上最后一段。
这是通过为哺乳动物和WingedAnimal提供一个vtable指针(或“v指针”)来实现的,因为,例如,在哺乳动物和它的动物部分的开头之间的内存偏移直到运行时才是未知的。这样蝙蝠就变成了(动物,哺乳动物,动物,WingedAnimal,蝙蝠,动物)。有两个vtable指针,每个继承层次结构都有一个,它们实际上继承了pointers。在本例中,一个用于哺乳动物,另一个用于WingedAnimal。因此,对象的大小增加了两个指针,但是现在只有一个动物,没有歧义。Bat类型的所有对象都将具有相同的指针,但每个Bat对象将包含其自己的唯一动物对象。如果另一个类继承了哺乳动物,如松鼠,那么松鼠中的哺乳动物对象中的v指针将与蝙蝠中的哺乳动物对象中的v指针不同,尽管它们在特殊情况下仍然可以是相同的,即对象的松鼠部分与蝙蝠部分具有相同的大小,因为从哺乳动物到动物部分的距离是相同的。vtables并不是完全相同的,但是它们中的所有基本信息(距离)都是。
能不能再给我点线索。
发布于 2010-07-04 19:08:44
有时,您确实需要看到一些代码/图表:)注意,标准中没有提到这个实现细节。
首先,让我们看看如何在C++中实现方法:
struct Base
{
void foo();
};这类似于:
struct Base {};
void Base_foo(Base& b);事实上,当您查看调试器中的方法调用时,您通常会看到this参数是第一个参数。它有时被称为隐式参数。
现在,转到虚拟表上。在C和C++中,可以有指向函数的指针。vtable本质上是指向函数的指针表:
struct Base
{
int a;
};
void Base_set(Base& b, int i) { b.a = i; }
int Base_get(Base const& b) { return b.a; }
struct BaseVTable
{
typedef void (*setter_t)(Base&, int);
typedef int (*getter_t)(Base const&);
setter_t mSetter;
getter_t mGetter;
BaseVTable(setter_t s, getter_t g): mSetter(s), mGetter(g) {}
} gBaseVTable(&Base_set, &Base_get);现在我可以做这样的事情:
void func()
{
Base b;
(*gBaseVTable.mSetter)(b, 3);
std::cout << (*gBaseVTable.mGetter)(b) << std::endl; // print 3
}现在,继续继承。让我们创建另一个结构
struct Derived: Base {}; // yeah, Base does not have a virtual destructor... shh
void Derived_set(Derived& d, int i) { d.a = i+1; }
struct DerivedBaseVTable
{
typedef void (*setter_t)(Derived&,int);
typedef BaseVTable::getter_t getter_t;
setter_t mSetter;
getter_t mGetter;
DerivedBaseVTable(setter_t s, getter_t g): mSetter(s), mGetter(g) {}
} gDerivedBaseVTable(&Derived_set, &Base_get);以及使用:
void func()
{
Derived d;
(*gDerivedBaseVTable.mSetter)(d, 3);
std::cout << (*gDerivedBaseVTable.mGetter)(d) << std::endl; // print 4
}但是如何实现自动化呢?
那么,在多重继承的情况下会发生什么呢?在内存布局方面,继承非常类似于组合:
| Derived |
| BaseA | BaseB |
| vpointer | field1 | field2 | padding? | vpointer | field1 | field2 | padding? |因此,MostDerived将有两个虚拟表:一个用于更改BaseA中的方法,另一个用于更改BaseB中的方法。
纯虚拟函数通常表示为相应字段中的空指针(简单地)。
最后,建筑和破坏:
施工
BaseA:首先初始化v指针,然后执行属性,然后执行构造函数的主体。BaseB是构建的:v指针、属性、体Derived是构建的:替换指针(都是)、属性、主体破坏
Derived is destructed:析构函数的主体,销毁属性,将基本指针放回BaseB被破坏:身体,属性BaseA被破坏:身体,属性我认为这是相当全面的,我会很高兴,如果有一些C++大师可以审查这一点,并检查我没有犯任何愚蠢的错误。另外,如果有什么遗漏了,我很乐意补充一下。
发布于 2010-07-04 17:06:45
我不能真的。本节试图描述如何在C++实现中使用虚拟方法表来提供动态绑定(在多重继承的情况下)。
如果你没有做编译器,我的建议是:不用麻烦。阅读您最喜欢的关于继承、虚拟方法、多重继承和虚拟继承的C++书籍。
另外,C++标准(IIRC)不需要使用vtable,而是实现细节。所以说真的,别费心了。
发布于 2010-07-04 17:13:30
正如mkluwe所建议的,指针实际上不是语言的一部分。然而,了解实现技术可能是有用的,特别是在像C++这样的低级语言中。
如果你真的想学这个,我会推荐在C++对象模型中,它解释了这个和很多其他细节。
https://stackoverflow.com/questions/3175437
复制相似问题