我最近一直在绕道而行,并且随之而来。我绕道了很多不同的功能; thiscall,stdcall,cdecl,虚函数等。但有一件事我没有管理(甚至可能不可能),那就是挂钩基类虚函数。例如;有一个Car类声明了一个虚函数(空)Drive
。然后还有3个继承汽车并实施Drive
的汽车类。
如果我挂钩Car(基类)Drive
函数(使用简单的'jmp'钩子),它会被Car
的后代触发,当它们触发Drive
时,如果他们不调用基本函数?
更彻底地解释:
class Car
{
virtual void Drive(void) { } // Empty virtual function
}
class Lamborghini : public Car
{
void Drive(void) { // does lots of stuff, but does NOT call base function }
}
所以我想知道基本方法是否被调用或是否可以以某种方式挂钩?函数exectution是否直接跳转到<{em>}或者它是否以某种方式通过Lamborghini::Drive
类,因此只要后代调用Car
就可以检测到它?
编辑:如果基类函数为空,是否可以挂钩它,因为它需要5个字节的空间?
答案 0 :(得分:5)
不,基本方法不会自动调用 。动态调度机制将检测它需要调用哪个覆盖,这将是被调用的函数。这通常通过虚拟表(vtable)实现,该表存储指向类中每个虚函数的最终重写的指针。当使用动态分派时,编译器通过该表注入间接调用并跳转到正确的函数。
请注意,vtable实际上保存了指向 thunks 或 trampolines 的指针,这些指针可能会在转发调用之前修改this
(隐含的第一个参数)。使用此方法的优点是,如果不需要更新this
,编译器可以直接跳转到最终的覆盖。无论如何,您可以利用此功能并修改vtable以指向您自己的代码(即您可以更新每个vtable中的指针 - 每种类型 - 指向您自己的 thunk 或功能)
答案 1 :(得分:0)
如果我的问题正确,将根据虚函数表调用Lamborghini类中的方法Drive。如果要调用基类的Drive方法,则必须编写类似Car::Drive;
的内容。由于VTBL,基类需要一些空间。希望我的问题没有答案。
答案 2 :(得分:0)
如果我理解正确,您希望每次调用Car::Drive
时都调用Lamborghini::Drive
,即使Lamborghini:Drive
没有直接调用基函数?
为此,最简单的方法是使用“内部”函数,该函数将是虚拟的(并受保护),而初始方法将是非虚拟的并将路由调用。 这是一个例子:
class Car
{
void Drive(void)
{
// ...
Car::innerDrive(); // Base function call
// ...
this->innerDrive(); // 'Derived' function call
// ...
}
protected:
virtual void innerDrive(void) { } // Empty virtual function
}
class Lamborghini : public Car
{
protected:
void innerDrive(void) { // does lots of stuff, but does NOT call base function }
}