函数重载和虚方法表

0 c++ overloading

可能的重复:
C++ 中的切片问题是什么?

我有一个简单的代码作为多态和继承的例子

class A
{
public:
    int fieldInA;

    void virtual overloadedFunc()
    {
        printf("You are in A\n");
    }
};

class B : public A
{
public:
    int fieldInB;

    void overloadedFunc()
    {
        printf("You are in B\n");
    }
};

void DoSmth(A* a)
{
    a->overloadedFunc();
}

void DoSmthElse(A a)
{
    a.overloadedFunc();
}
int _tmain(int argc, _TCHAR* argv[])
{
    B *b1 = new B();
    B b2;
    //Breakpoint here
    DoSmth(b1);
    DoSmthElse(b2);
    scanf("%*s");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我停在断点处时,b1 的 _vfptr[0] 和 b2 的 _vfptr[0] 的值是相同的(SomeAddr(B::overloadedFunc(void)))。在 DoSmth() 中将 b1 作为参数传递后,局部变量 a 的 _vfptr[0] 仍然是 someAddr(B::overloadedFunc(void)),但 DoSmthElse 中 a 的 _vfptr[0] 现在是 someAddr(A::overloadedFunc(void) ))。我确定这是我对函数重载概念的一些误解,但我无法理解,为什么在第一种情况下我看到“你在 B”和第二个“你在 A”。同 A *b1 = new B(); DoSmth(b1); // 你在B,为什么?

Die*_*ühl 5

首先,您需要正确使用术语!您没有重载任何函数,而是覆盖了它们:

  • 重载意味着您具有相同的函数名称和不同类型的参数。选择正确的重载是一个编译时操作。
  • 覆盖意味着您拥有具有多态(在 C++ 中virtual)函数的类层次结构,并且您将被调用的函数替换为适用于更专业类的对象的函数。你覆盖了原来的意思。选择正确的覆盖是一个运行时操作,在 C++ 中使用类似于虚拟函数表的东西。

这些术语令人困惑,更糟糕的是,它们甚至相互作用:在编译时选择正确的重载,最终调用可能被覆盖的虚函数。此外,覆盖派生类可能会隐藏从基类继承的重载。但是,如果您无法弄清楚条款,所有这些都可能毫无意义!

现在,对于您的实际问题,当您调用时,DoSmthElse()您将对象b2按值传递给采用类型为 的对象的函数A。这A通过复制A对象的子对象来创建类型的B对象。但是由于B是从 派生的A,所以并不是所有的B都被表示出来,也就是说,A你在其中看到的对象的DoSmthElse()行为不像一个B对象,而是一个A对象。毕竟,它一个A对象而不是一个B! 这个过程通常称为切片:您将B对象的某些部分切掉,使其变得特别。