好吧,我的问题有点棘手。 假设我有三个类,如此:
class GrandFather
{
public:
virtual int DoSomething()
{
return 3;
}
};
class Father : public GrandFather
{
};
class Child : public Father
{
public:
virtual int DoSomething()
{
Father::DoSomething();
}
};
我在一些参考文献中发现,在调用基函数时,不使用整个虚拟机制,并且会发生名称重整。
现在我想知道如何做到这一点。
Child类有一个指向其自己的vtable的指针,它将指示在调用DoSomething()
时调用子实现。
父类也有一个指向自己的vtable的指针,这表明在调用DoSomething()
时,会调用GrandFather的实现。
当我在Child中使用Father::DoSomething()
时,应该调用GrandFather::DoSomething()
,
但是Child如何判断函数的位置?
如果确实使用了名称修改,那么如何?因为没有该名称的功能(类似_Father_DoSomething(this)
)。
孩子必须访问父亲的vptr才能到达GrandFather::DoSomething()
,据我所知,他不能。{/ p>
这已经困扰了我很长一段时间,所以我非常感谢你的帮助。 谢谢:))
答案 0 :(得分:1)
无论何时显式限定成员函数,都表示要在该特定类中调用该特定函数,并且不使用虚拟调用机制。虚拟调用仅在您调用成员函数而不限定它时发生,在这种情况下它使用虚拟机制来决定使用哪个类的成员函数。
调用Father::DoSomething
调用GrandFather :: DoSomething的事实是由于继承,这是一个单独的机制。如果你引用了派生类的一个成员而它不在那里,它会上升一级并在基类中查找它。那里不需要虚拟电话。
答案 1 :(得分:1)
当您从Father::DoSomething
调用Child
时,编译器使用编译时信息来计算要调用的内容。因为Father
中没有版本,所以它知道在GrandFather
中调用该版本,因为它是Father
范围内有效的版本。
当重写的方法调用基本实现时,不使用vtable。 vtable仅在通过指针或引用调用方法时使用。这就是在C ++中实现所有多态的方式。
名称修改与此无关。名称修改基本上是如何编码方法名称,因此为方法/函数指定唯一名称。没有两个方法/函数具有相同的错位名称。
答案 2 :(得分:1)
使用限定名称命名函数时,该函数 调用是在编译时确定的,使用静态类型 表达式,名称查找从给定的位置开始 由资格赛。因为要调用的函数是确定的 完全通过静态查找,不需要访问任何vtable 一点都不。
答案 3 :(得分:1)
g ++ file_name.cpp -S命令可以提供足够的信息以清除所有与vtable相关的问题。请检查生成的.s文件:
Child拥有自己的vtable,其中包含父vtable,它依次包含GrandFather的vtable:
vtable for Child:
Child::DoSomething()
vtable for Father
vtable for Father:
GrandFather::DoSomething()
vtable for GrandFather
vtable for GrandFather:
GrandFather::DoSomething()
当我在Child中使用Father :: DoSomething()时,它应该调用 GrandFather :: DoSomething(),但是Child如何判断函数的位置 是
父亲的vtable引用了GrandFather :: DoSomething(),所以调用Father :: DoSomething()你实际上是在调用GrandFather :: DoSomething()
答案 4 :(得分:1)
“名字错误”与它完全无关。被称为“名称修剪”的技术属于完全不同且不相关的区域。我不知道你有什么想法让它参与其中。
类没有任何“指向vtable的指针”。只有类的特定对象(也称为实例)可能有这样的指针。不要混合类和类类型的对象。在任何情况下,“vtable指针”是在语言级别不存在的实现细节。在语言层面理解代码的行为是完全没有必要的。
在您的示例中,您根本没有任何对象。你只是声明了一堆类。出于这个原因,要及早采取任何“指向vtable的指针”。您没有任何指向任何vtable的指针。
谈到Father::DoSomething()
调用的问题,任何“虚拟表”的问题根本不会出现在图片中,即使是作为实现细节。 Father::DoSomething()
调用使用目标函数的限定名称。这种合格的调用总是直接解决,不涉及任何vtable。即通过执行Father::DoSomething()
,您明确要求编译器忽略任何多态(忽略任何“vtable”)并直接对类DoSomething
中的名称Father
执行编译时名称查找。根据名称查找规则,它将找到函数GrandFather::DoSomething()
并调用它。
如果您实际声明了一个对象,例如
Child child;
然后您将GrandFather
子对象嵌入到嵌入上述Father
对象的Child
子对象中。这些嵌套对象中的所有“vtable指针”都将指向Child
的vtable(事实上,在典型的实现中,所有这些嵌套对象将共享一个vtable指针)。
现在,如果你打电话
child.DoSomething()
此调用将根据Child
的vtable解析并发送到Child::DoSomething()
(大多数编译器实际上足够聪明以优化代码并直接调度呼叫)。但是,如上所述,正如您所问,从Father::DoSomething
内部Child::DoSomething
的合格调用是无条件直接执行的。它不关心任何vtable指针。它直接进入GrandFather::DoSomething()
。
这就是它的全部内容。