当中间类跳过实现时,在继承层次结构中执行哪个虚方法?

时间:2018-04-05 12:44:13

标签: c++ class polymorphism virtual undefined-behavior

我确定之前有人问过这个问题,但我根本不知道该搜索什么。所以我很乐意在有人指出我类似的问题后立即删除这个问题。如果有人有更好的建议,我也很乐意重新命名: - )

我想知道以下代码是否按标准定义了行为,或者这可能是编译器/平台依赖的:

struct A
{
    virtual void f()
    {
        std::cout << "A::f()" << std::endl;
    }
};

struct B : public A
{
    // f() is not implemented here
};

struct C : public B
{
    virtual void f() override
    {
        B::f(); // call f() of direct base class although it is not implemented there
        std::cout << "C::f()" << std::endl;
    }
};

int main()
{
    A* pA = new C();
    pA->f();
}

Visual Studio 2017和gcc 5.4.0的输出是:

A::f()
C::f()

编译器是否会在层次结构中向上搜索,直到找到实现?你能链接到C ++标准吗?我通过在纯虚拟中创建f()来测试它,链接器很好地告诉我有一个未解析的符号。我能依靠吗?

据我所知,使用像B :: f()这样的范围运算符总是调用非虚拟版本。所以没有多态现象发生,是吗?

编辑:带有误导性的print语句,将“B :: f()”替换为“C :: f()”。

1 个答案:

答案 0 :(得分:3)

指针的动态类型

A* pA = new C();

C *

因此C类中的虚函数被称为

struct C : public B
{
    virtual void f() override
    {
        B::f(); // call f() of direct base class although it is not implemented there
        std::cout << "B::f()" << std::endl;
    }
};

B类没有重新定义基类A的虚函数。所以在本声明中

        B::f(); // call f() of direct base class although it is not implemented there

调用类A中定义的虚函数。这是指向B类虚函数的指针表,其中包含A类中定义的函数的地址。

在此次电话会议中

B::f();

可以访问类B的虚函数表,该表包含类A中函数定义的地址,因为该函数未在B类中被覆盖。

从C ++标准(5.2.2函数调用)

  
      
  1. ...如果所选函数是非虚拟的,或者类成员访问表达式中的id-expression是qualified-id,那么该函数   叫做。否则,它是动态类型的最终覆盖(10.3)   调用对象表达式;这样的呼叫被称为a   虚函数调用。 [
  2.