意外输出...函数绑定如何在虚拟 table 中发生
Unexpected Output...how function binding happens in virtual table
class Base
{
public:
int a;
virtual void fun1()
{
cout<<"Hello Base"<<endl;
}
void fun2()
{
fun1();
}
};
class Derived: public Base
{
int a;
void fun1()
{
cout<<"Hello Derived"<<endl;
}
};
int main()
{
Base * B = new Derived;
B->fun2();
return 1;
}
请帮我理解为什么输出是 Hello Derived.How 这个函数绑定需要 place.How 是虚拟的 table 为 Base 创建的条目和派生的 class.
伪代码如下所示:
#include <iostream>
class Base{
protected:
void **vt_ptr;
public:
int a;
//Executed prior to base member initialization
//and reexecuted prior to Base destructor call
void set_dynamic_type(){
vt_ptr = Base::vtable;
}
/*virtual*/
void fun1(){
reinterpret_cast<void(*)(Base&)>(vt_ptr[1])(*this);
}
void fun2(){
fun1();
}
private:
static void func1_def(Base& pseudo_obj_arg){
Base* this=&pseudo_obj_arg;
std::cout<<"Hello Base"<<std::endl;
}
static void* vtable[2];
};
void* Base::vtable[2]={
reinterpret_cast<void*>(&type_id_of_Base),
reinterpret_cast<void*>(&Base::func1_def)};
class Derived: public Base
{
int a;
//Executed after Base intialization,
//before Derived member initialization.
//Reexecuted prior to Derived destructor call
void set_dynamic_type(){
Base::vt_ptr = Derived::vtable;
}
private:
static void func1_def(Base& pseudo_obj_arg){
Derived* this=static_cast<Derived*>(&pseudo_obj_arg);
std::cout<<"Hello Derived"<<std::endl;
}
static void* vtable[2];
};
void* Derived::vtable[2]={
reinterpret_cast<void*>(&type_id_of_Derived),
reinterpret_cast<void*>(&Derived::func1_def)};
也是一个合格的调用,如:obj.Base::func1()
直接调用Base::func1_def(obj)
,否则会抛出Base::func1
.
中描述的去虚拟化过程
虚拟 table 是在构造 class 对象时创建的。当你构造一个 Derived
对象时,它将首先调用 Base
构造函数(它创建 vtable 并将它自己的 Base::fun1
写入其中。然后 Derived
构造函数运行并用自己的实现 (Derived::fun1
).
覆盖 fun1
的 vtable 条目
如果您随后在任何时候(甚至在任何 Base
函数内)调用此类对象实例的 fun1
,它将查看 vtable 并调用它在那里找到的任何功能。正如上面所解释的,Derived::fun1
在构造后 Derived
对象的 vtable 中,因此这就是将被调用的对象。您当前处于 Base
函数并不重要,vtable 条目不会更改。
请注意,在 构造期间,vtable 未完全设置:如果您要从 [=11= 中调用 fun1
] 构造函数,你会 不 调用 Derived::fun1
但 Base::fun1
因为 Derived
还没有替换 vtable 条目。
另请注意,完全指定函数(例如,在 Derived
实例上调用 Base::fun1()
)不会执行 vtable 查找,而是使用指定的函数。
class Base
{
public:
int a;
virtual void fun1()
{
cout<<"Hello Base"<<endl;
}
void fun2()
{
fun1();
}
};
class Derived: public Base
{
int a;
void fun1()
{
cout<<"Hello Derived"<<endl;
}
};
int main()
{
Base * B = new Derived;
B->fun2();
return 1;
}
请帮我理解为什么输出是 Hello Derived.How 这个函数绑定需要 place.How 是虚拟的 table 为 Base 创建的条目和派生的 class.
伪代码如下所示:
#include <iostream>
class Base{
protected:
void **vt_ptr;
public:
int a;
//Executed prior to base member initialization
//and reexecuted prior to Base destructor call
void set_dynamic_type(){
vt_ptr = Base::vtable;
}
/*virtual*/
void fun1(){
reinterpret_cast<void(*)(Base&)>(vt_ptr[1])(*this);
}
void fun2(){
fun1();
}
private:
static void func1_def(Base& pseudo_obj_arg){
Base* this=&pseudo_obj_arg;
std::cout<<"Hello Base"<<std::endl;
}
static void* vtable[2];
};
void* Base::vtable[2]={
reinterpret_cast<void*>(&type_id_of_Base),
reinterpret_cast<void*>(&Base::func1_def)};
class Derived: public Base
{
int a;
//Executed after Base intialization,
//before Derived member initialization.
//Reexecuted prior to Derived destructor call
void set_dynamic_type(){
Base::vt_ptr = Derived::vtable;
}
private:
static void func1_def(Base& pseudo_obj_arg){
Derived* this=static_cast<Derived*>(&pseudo_obj_arg);
std::cout<<"Hello Derived"<<std::endl;
}
static void* vtable[2];
};
void* Derived::vtable[2]={
reinterpret_cast<void*>(&type_id_of_Derived),
reinterpret_cast<void*>(&Derived::func1_def)};
也是一个合格的调用,如:obj.Base::func1()
直接调用Base::func1_def(obj)
,否则会抛出Base::func1
.
虚拟 table 是在构造 class 对象时创建的。当你构造一个 Derived
对象时,它将首先调用 Base
构造函数(它创建 vtable 并将它自己的 Base::fun1
写入其中。然后 Derived
构造函数运行并用自己的实现 (Derived::fun1
).
fun1
的 vtable 条目
如果您随后在任何时候(甚至在任何 Base
函数内)调用此类对象实例的 fun1
,它将查看 vtable 并调用它在那里找到的任何功能。正如上面所解释的,Derived::fun1
在构造后 Derived
对象的 vtable 中,因此这就是将被调用的对象。您当前处于 Base
函数并不重要,vtable 条目不会更改。
请注意,在 构造期间,vtable 未完全设置:如果您要从 [=11= 中调用 fun1
] 构造函数,你会 不 调用 Derived::fun1
但 Base::fun1
因为 Derived
还没有替换 vtable 条目。
另请注意,完全指定函数(例如,在 Derived
实例上调用 Base::fun1()
)不会执行 vtable 查找,而是使用指定的函数。