虚拟功能和绕行

时间:2012-05-08 12:23:10

标签: c++ gcc virtual-functions detours

我最近一直在绕道而行,并且随之而来。我绕道了很多不同的功能; 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个字节的空间?

3 个答案:

答案 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 }
}