据我了解,virtual
对象中函数指针表的位置取决于编译器。
将此指针放在对象的开头与结尾是否有任何优点/缺点,反之亦然?
2 回答
虚函数表的存在取决于编译器(但所有编译器都这样做),并且位置也不是强制性的......在我知道详细信息的所有编译器中,vptr 存储在对象的开头。原因是它提供了一个统一的位置。考虑一个类层次结构:
struct base {
T data;
virtual void f();
};
struct derived : base {
T1 data;
virtual void g();
};
如果 vptr 存储在对象的末尾,那么它将在sizeof(T)
完整类型对象的字节之后base
。现在,当您有一个完整类型的对象时derived
,base
子对象的布局必须与完整base
对象的布局兼容,因此vptr
仍然必须是sizeof(T)
对象内部的字节,这将位于derived
对象中间的某个位置(sizeof(T)
从头到尾sizeof(T1)
)。所以它将不再位于对象的末尾。
此外,给定一个this
指针,虚拟调用需要通过 vtable 进行间接调用,这基本上是取消引用vptr
,添加偏移量并跳转到存储在那里的内存位置。如果vptr
存储在对象的末尾,对于每个虚拟调用,this
在取消引用vptr
.
是的,它完全依赖于实现。
对于简单的继承层次结构,它位于对象的开头,但对于复杂的层次结构,它不会。
无论如何,您编写的任何源代码都不应该依赖于它所在的位置,实际上您编写的任何代码都不应该依赖于虚拟表或虚拟表指针的存在。
C++ 标准并没有强制要求通过虚拟表和指针来实现虚拟调度,一个实现可以自由地使用其他实现方法来实现,但是所有主流编译器都通过表指针机制来实现这一点,需要注意的重要一点是它们可能会有所不同在指针所在位置的精确实现等。