2

我试图理解 C++ 中的虚函数。

struct B {
  int f() { return 1;}
}

struct D : B {
  int f() { return 1;}
}

在主函数中:

B* b = new D;
b.f()

我的理解是基类和派生类之间存在“竞争”:它们都有一个同名和同一个签名的函数。当b.f()被调用时,只会选择其中一个。在虚拟情况下:

  • 根据 b 指向的对象的类型选择获胜者
  • 该选择是在运行时做出的

在非虚拟情况下:

  • 根据指针 b 的类型选择获胜者
  • 该选择是在编译时做出的

我不明白两者之间的因果关系

  1. virtual关键字的使用
  2. 查找 b 指向的对象类型的能力
  3. 编译时间与运行时间

例如,为什么我们不能在编译时执行 (2)?

4

3 回答 3

1

经常有在编译时无法知道类型的情况。例如,考虑一个游戏,其中您有一些物理对象(实体)并且每个对象在接触时可能表现不同。例如

struct Entity {
   int x,y,w,h;
   virtual void onPlayerContact() {}
};

struct ExitDoor : Entity {
   void onPlayerContact() { exitLevel(); }
};

struct Monster : Entity {
   void onPlayerContact() { diePlayer(); }
};

//...

现在您将所有现有实体保存在一个大列表中,并且在每一帧中,您都会遍历列表,检查您的玩家是否与实体有联系,如果有,则调用onPlayerContact. IE:

static std::set<Entity*> entities;
static Player* player;

void frame() {
   for(Entity* entity : entities) {
      if(player->contacts(entity))
         entity->onPlayerContact(); // it's only known at runtime what to call here
   }
}
于 2013-10-21T07:47:42.747 回答
1

Here is a simple example

void some_function(B* b)
{
    b.f();
}

int main()
{
    int i;
    cin >> i;

    if (i == 0)
    {
         B *b = new B();
         some_function(b);
    }
    else
    {
         D *d = new D();
         some_function(d);
    }

     return 0;
}

In compile time, you don't know the exact type of the object passed to the function "some_function(B* b)". It should be decided at run-time.

于 2013-10-21T08:08:07.530 回答
0

您可以执行 (2),前提是您执行 (1),使用virtual. 你做(2)与typeid。一般来说,这不是最高效的方法。(反馈效应:它很少有用,很少优化,这使得它更不被使用,等等)。

依赖的原因是virtual启用了 RTTI(运行时类型信息),这也是 2 所需要的。RTTI 的一种常见形式是所谓的vtable,它是一个包含指向给定类的虚函数的指针的表。每个具有虚函数的对象都有一个指向该表的指针。typeid可以通过几种方式(嵌入、数据指针、指向返回它的函数的指针等)将信息添加到这样的表中。但是除了指向 a 的指针之外,还有其他实现 RTTI 的选项vtable,所以不要认为这是唯一的方法。

您还想知道为什么不能在运行时执行此操作。考虑以下代码

void Foo(std::ostream&);
int main(int argc, char **argv)
{
  if (argc == 2)
  {
    std::ofstream outFile(argv[1]);
    Foo(outFile);
  }
  else
  {
     Foo(std::cout);
  }
}

显然,在编译时,Foo您不知道在运行时会得到什么。这取决于命令行。在编译时,你只知道你会得到一个ostream&.

于 2013-10-21T07:42:27.067 回答