意外输出..函数绑定在虚拟表中的发生方式
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.这个函数绑定是如何发生的。如何为 Base 类和派生类创建虚拟表条目。
虚拟表是在构造类对象时创建的。当您构造一个Derived
对象时,它将首先调用Base
构造函数(该构造函数创建 vtable 并将自己的Base::fun1
写入其中。然后,Derived
构造函数运行并使用自己的实现 (Derived::fun1
) 覆盖 vtable 条目以供fun1
。然后,如果您在以后的任何时间点(甚至从任何Base
函数中)调用此类对象实例的fun1
,它将查看 vtable 并调用它在那里找到的任何函数。如上所述,构造后Derived
对象的 vtable 中是Derived::fun1
,因此这是将被调用的。无论您当前处于Base
函数中,vtable 条目都不会更改。
请注意,在构造过程中,vtable 尚未完全设置:如果要从Base
构造函数中调用fun1
,则不会调用Derived::fun1
而是Base::fun1
,因为Derived
尚未替换 vtable 条目。
另请注意,完全指定函数(例如,在Derived
实例上调用Base::fun1()
)不会执行 vtable 查找,而是完全使用指定的函数。
伪代码如下所示:
#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
中描述的去虚拟化过程。
相关文章:
- 如何在c++中为模板函数实例创建快捷方式
- 虚拟决赛作为安全
- PowerPC ppc64le上的Gcc Woverloaded虚拟错误
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- 以螺旋方式打印矩阵的程序.(工作不好)
- 意外输出..函数绑定在虚拟表中的发生方式
- 如何以编程方式确定网络适配器在 Windows 上是否为虚拟适配器?
- 确定范围是访问虚拟功能的合法方式吗?
- 虚拟和非虚拟成员函数的调用方式有什么区别?
- 升级到以多种方式为基类的C 类(不必使用虚拟继承)
- 如何以编程方式捕获 Oracle 虚拟盒子机器的屏幕
- C++-创建虚拟函数以打印调试消息的最佳方式
- 这种使用虚拟受保护方法扩展库的方式是否安全
- 使用虚拟方法组织单例的最佳方式
- 如何以编程方式区分由 subst 命令创建的虚拟驱动器和实际的可移动驱动器
- 在C++中定义虚拟继承的两种不同方式
- 以编程方式挂载微软虚拟硬盘驱动器(VHD)
- 以非多态方式调用虚拟函数的成本是多少
- 如何以编程方式确定网卡是虚拟网卡