当使用vptr直接调用虚拟函数时,了解输出
Understanding output when virtual functions are called directly using vptr
我正在仔细阅读从某处获得的代码,以了解vptr和vtable是如何工作的。以下是输出的代码
class Base1
{
virtual void fun1() { cout<< "Base1::fun1()" << endl; }
virtual void func1() { cout<< "Base1::func1()" << endl; }
};
class Base2 {
virtual void fun1() { cout<< "Base2::fun1()" << endl; }
virtual void func1() { cout<< "Base2::func1()" << endl; }
};
class Base3 {
virtual void fun1() { cout<< "Base3::fun1()" << endl; }
virtual void func1() { cout<< "Base3::func1()" << endl; }
};
class Derive : public Base1, public Base2, public Base3
{
public:
virtual void Fn()
{
cout<< "Derive::Fn" << endl;
}
virtual void Fnc()
{
cout<< "Derive::Fnc" << endl;
}
};
typedef void(*Fun)(void);
int main()
{
Derive obj;
Fun pFun = NULL;
// calling 1st virtual function of Base1
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);
pFun();
// calling 2nd virtual function of Base1
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
pFun();
// calling 1st virtual function of Base2
pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0);
pFun();
// calling 2nd virtual function of Base2
pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1);
pFun();
// calling 1st virtual function of Base3
pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0);
pFun();
// calling 2nd virtual function of Base3
pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1);
pFun();
// calling 1st virtual function of Derive
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
pFun();
// calling 2nd virtual function of Derive
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
pFun();
return 0;
}
OUTPUT:
Base1::fun
Base1::func
Base2::fun
Base2::func
Base3::fun
Base3::func
Derive::Fn
Derive::Fnc
看起来还可以,但派生类的虚拟函数的调用方式还不清楚。不应该是这样吗:
// calling 1st virtual function of Derive
pFun = (Fun)*((int*)*(int*)((int*)&obj+3)+0);
pFun();
// calling 2nd virtual function of Derive
pFun = (Fun)*((int*)*(int*)((int*)&obj+3)+1);
这意味着是使用派生类的vptr访问的虚拟函数的地址,其最终指向派生类的vtable。
面向对象编程的全部思想是遵循抽象。当您有用于动态绑定的虚拟函数时,通过调用基类指针的虚拟函数来通过抽象使用它。根据它在类层次结构中动态指向的位置,它将动态绑定。为什么要更深入地打破抽象并使用vtbl等(根据某些指导原则,不同编译器的实现不同(。因此,建议本着良好的精神使用动态绑定。
看起来Derive
中的新虚拟函数被添加到第一个基类的vtable的末尾,而不是放在一个单独的表中。这是有道理的:扩展一个现有的表比添加一个额外的表更有效,因为这会为每个继承级别增加一个指针来扩展每个对象。
当然,所有这些都取决于实现。该语言没有指定应该如何实现虚拟调度,只指定在正常使用时应该如何工作。
相关文章:
- 了解每月第一天函数的代码
- 了解构造函数在移动、复制、赋值语义中的行为
- 检查模板中 nullptr 的函数指针,了解任何类型的可调用对象
- 了解在返回值之前和之后使用 EAX 的函数调用
- 了解模板函数(源代码为 .h)与其编译的 .lib 的关系
- 构造函数是否有一种现代C++方法来了解其'container'类?
- 了解类构造函数的静态强制转换
- 了解shared_ptr传入函数时引用计数何时递增
- 确认了解指向函数的指针
- 我想了解为什么在这个例子中使用引用函数?或者引用在c++函数中的重要性
- 了解从多个类派生时的虚函数
- 了解递归函数的执行顺序
- 了解元函数以在类型包中查找类型
- 了解复制构造函数和引用
- 了解函数返回对象的移动语义
- 了解派生类中C++析构函数的行为
- 了解类构造函数中的"内联"C++?
- 了解C++中函数的值类别
- C++11使variadic构造函数了解一个初始化列表的初始化列表
- 复制构造函数 - 了解问题