4

我有以下代码:

#include <iostream>
using namespace std;

class Base 
{
public:
    virtual void WhoAmI() const;
    typedef void (Base::*WhoPtr)() const;
};

class Derived : public Base 
{
public:
    virtual void WhoAmI() const;
};

void Derived::WhoAmI() const 
{
    cout << "I am the derived" << endl;
}

void Base::WhoAmI() const 
{
    cout << "I am the base" << endl;
}

int main() 
{
    Base::WhoPtr func = &Base::WhoAmI;
    Base theBase;
    (theBase.*func)();
    Derived theDerived;
    (theDerived.*func)();
    cin.get();
    return 0;
}   

让我们专注于主要:

int main() 
{
    Base::WhoPtr func = &Base::WhoAmI;
    Base theBase;
    (theBase.*func)();
    Derived theDerived;
    (theDerived.*func)();
    cin.get();
    return 0;
}   

我们有一个局部变量func,它保存着 的地址Base::WhoAmI

此外,我们有BaseDerived对象。

在第 2 行,我们调用func从基点指向的点:(theBase.*func)()

直到现在我才明白。

2 行之后,我们将其称为派生:(theDerived.*func)().

它打印:I am the derived. 为什么?

两者WhoAmI都是virtual,这意味着调用依赖于pointed object,而不是类型。

指向的对象是func属于谁Base。为什么打印I am the derived而不是打印I am the base

4

3 回答 3

1

你为什么惊讶。您有一个指向成员函数的指针,该指针指向一个函数。如果您获取 的地址 theDerived或对它的引用,并用它初始化 aBase*或 a Base&,您会期望ptrToBase->WhoAmI()在派生类中调用该函数。毕竟,这就是您开始使用虚函数的原因。当您通过指向成员函数的指针进行调用时,同样的情况也成立。该表达式 &Base::WhoAmI产生一个指向(虚拟)成员函数的指针。

于 2013-07-28T17:08:31.927 回答
0

指向的对象是theDerived。您选择的方法是Base::whoAmI,请注意方法名称包含类引用(静态)但不包含对象引用(动态)。调用什么虚函数取决于this方法所使用的对象的运行类型时间。

于 2013-07-28T16:57:58.997 回答
0

关于虚函数的全部意义在于,它是运行时根据所讨论对象的动态类型来决定调用哪个版本。这与非虚拟函数调用非常不同,其中编译器本身根据对象的声明类型做出决定,而与实际运行时对象的类型无关。

为了实现这一点,每个类都有一个虚函数表(vtable),它的所有实例在运行时都有一个隐式指针。现在,当您创建 Base 的实例时,该实例的 vtable 指针将指向 Base 的 vtable。同样,Derived 的实例将具有指向 Derived 的 vtable 的指针。

在这两个 vtable 中,您的示例中只有一个条目WhoAmI(),Base 的 vtable 中的指针指向,Base::WhoAmI()而 Derived 的 vtable 中的指针指向Derived::WhoAmI()

因此,当您调用WhoAmI()运行时将从对象中查找 vtable,然后查找指向将要执行的函数的函数指针。

这就是说,从您所看到的行为中可以明显看出,成员函数指针是什么:只不过是 vtable 的偏移量!在您的情况下,此偏移量很可能只是零,因为WhoAmI()它是 vtable 中的第一个也是唯一一个条目。当你调用成员函数指针后面的函数时,你给它一个对象,从中查找一个 vtable。然后 vtable 中的偏移量(成员函数指针)用于加载指向实际执行代码的指针,就像在任何其他对虚函数的调用中一样。

唯一的区别是,在普通的虚函数调用中,编译器将通过您调用的函数的名称知道查找函数指针的精确偏移量,当您使用成员函数指针时,该偏移量提供在运行时由成员函数指针。

于 2013-07-28T17:20:04.387 回答