use*_*057 8 c++ constructor virtual-functions vtable vptr
我知道对于任何具有虚函数的类或者从具有虚函数的类派生的类,编译器会做两件事.首先,它为该类创建一个虚拟表,然后,它将虚拟指针(vptr)放在该对象的基础部分中.在运行时,此vptr被分配并在对象实例化时开始指向正确的vtable.
我的问题是,在实例化过程中,这个vptr的确切位置是什么?这个vptr的赋值是否发生在构造函数之前/之后的对象的构造函数中?
Alo*_*ave 10
这严格依赖于实现.
对于大多数编译器,
编译器在每个构造函数的Member Initializer列表中初始化this - > __ vptr.
我们的想法是让每个对象的v指针指向其类的v-table,编译器为此生成隐藏代码并将其添加到构造函数代码中.就像是:
Base::Base(...arbitrary params...)
: __vptr(&Base::__vtable[0]) ? supplied by the compiler, hidden from the programmer
{
}
Run Code Online (Sandbox Code Playgroud)
这个 C++ FAQ解释了究竟发生了什么的要点.
指向vtable的指针在进入层次结构中的每个构造函数时更新,然后在每个析构函数的入口处再次更新.vptr将开始指向基类,然后在初始化不同级别时更新.
虽然你会从许多不同的人那里读到这是实现定义,因为它是vtable的全部选择,但事实是所有编译器都使用vtable,一旦你选择了vtable方法,标准确实要求它的类型运行时对象是正在执行的构造函数/析构函数的对象,这反过来意味着无论动态调度机制是什么,它都必须在遍历构造/销毁链时进行调整.
请考虑以下代码段:
#include <iostream>
struct base;
void callback( base const & b );
struct base {
base() { callback( *this ); }
~base() { callback( *this ); }
virtual void f() const { std::cout << "base" << std::endl; }
};
struct derived : base {
derived() { callback( *this ); }
~derived() { callback( *this ); }
virtual void f() const { std::cout << "derived" << std::endl; }
};
void callback( base const & b ) {
b.f();
}
int main() {
derived d;
}
Run Code Online (Sandbox Code Playgroud)
该标准规定的是该程序的输出base,derived,derived,base,但在呼叫callback是从所有的四个调用功能相同.它可以实现的唯一方法是在构造/销毁过程中更新对象中的vptr.