C++ 继承中的虚函数

Virtual function in Inheritance in C++

提问人:Jigar Patel 提问时间:2/8/2023 最后编辑:Jigar Patel 更新时间:2/8/2023 访问量:132

问:

**阅读以下提及代码**

#include<iostream>
using namespace std;

class FR
{
public :
    virtual int fun() 
    {
      cout<<"In FR Class "<<endl;
    }

    int Threading()
    {
        fun();
    }
};

class FD : public FR
{
public :
    int fun()
    {
        cout<<" In FD class "<<endl;
    }
};

int main()
{
    FD obj ;

    obj.Threading();
}

在这里,它的输出是“在 FD 类中”。

这里我们将 FR 类继承到 FD 类中,因此 FR 类的所有属性都是从基础类继承而来的, 但是当我们使用 FD 对象调用函数时,它会调用基于类,但对于线程类,函数是虚拟的,并且 Fun 定义也可用,因此 为什么它没有对 based 类函数进行分类。Threading()Fun()Fun()

我希望当我们调用该函数时,它应该被称为 FR 类函数而不是 FD 类。Threading()Fun()Fun()

实际输出 : “In FD Class”

预期输出 : “In FR Class”

C++ 继承虚拟纯 虚拟 运行时多态性

评论

1赞 463035818_is_not_an_ai 2/8/2023
obj因此调用方法调用,这就是虚拟的全部内容FDfunFD::fun
0赞 463035818_is_not_an_ai 2/8/2023
代码的作用称为模板方法模式
6赞 n. m. could be an AI 2/8/2023
你的期望是基于不完全理解什么。再读一遍那一章。virtual
0赞 Mark Ransom 2/8/2023
@463035818_is_not_a_number GOF 对模板的定义与C++定义不一致。
0赞 463035818_is_not_an_ai 2/8/2023
@MarkRansom是的,这个名字很不幸,这就是为什么我在提到它时总是链接一篇文章。

答:

3赞 463035818_is_not_an_ai 2/8/2023 #1

这被称为虚拟调度,基本上只是意味着更多。要调用的方法由对象的动态类型确定。virtual

你可以把这个调用看作是有一个:this->

class FR
{
public :
    virtual int fun() 
    {
      cout<<"In FR Class "<<endl;
    }

    int Threading()
    {
        this->fun();
    }
};

当对类型的对象进行调用时,在上面的代码中是 但是指向的对象的动态类型是 。因此,当调用虚拟时,它会调用 .ThreadingFDthisFR*thisFDfun()FD::fun()

如果不希望进行虚拟调度,请删除 .然后,您的代码将打印“In FR Class”。funvirtual

1赞 44stonelions 2/8/2023 #2

当您将方法声明为虚拟方法时,将为该类生成一个 vtable(如果它是具体的,即没有纯虚拟成员),其中包含指向该类中每个虚拟函数的指针。还将为使用虚拟方法派生自类的每个类生成一个 vtable(只要它们也是具体的)。

然后,该类的每个对象都会获得一个指向其特定 vtable 的 vtable 指针。您的类具有指向包含 的 vtable 的指针,而您的类具有指向包含 的 vtable 的指针。FRFR::funFDFD::fun

由于是非虚拟的,因此当在类的对象上调用时,使用指向该对象的指针调用实现的方法。然后,当调用时,它会在 的 vtable 中查找函数并调用 .ThreadingThreadingFDFRthisFDThreadingthis->funFDFD::fun

评论

0赞 463035818_is_not_an_ai 2/8/2023
vtable 是实现细节。当没有 vtable 时,OPs 代码也会产生相同的输出。
0赞 44stonelions 2/8/2023
@463035818_is_not_a_number我不确定这是否正确,但传递给的指针是 类型。要调用指向 an 的指针并获取实现的函数,您肯定必须通过 vtable?thisFR::ThreadingFR*funFRFD
0赞 463035818_is_not_an_ai 2/8/2023
我的意思是 c++ 标准没有提到 vtable,它只是指定了调用虚拟方法时会发生什么。例如,考虑一下去虚拟化(quuxplusone.github.io/blog/2021/02/15/devirtualization),其中不需要进行查找,因为它在编译时就已经知道了,在这种情况下,虚拟方法也可以正常工作。
0赞 44stonelions 2/8/2023
我不确定这些例子中是否有任何一个与这种情况完全匹配。但是,如果 OP 只对标准所说的内容感兴趣,他们就会将该帖子标记为语言律师。由于 vtable 是每个编译器在几乎每个有用情况下实现虚拟调度的方式,并且 OP 并不完全了解 virtual 关键字的含义,因此了解 vtable 以及它在这种情况下的实际工作方式对他们来说是有用的信息。
0赞 463035818_is_not_an_ai 2/8/2023
是的,这是有用的信息。虽然不应该本末倒置,但我认为补充一点也很有用,虚拟表只是一个实现细节
3赞 Vlad from Moscow 2/8/2023 #3

通过虚拟函数指针表调用虚拟函数。

派生类 FD 在其纠缠的虚函数指针中用它自己的覆盖函数的地址覆盖虚函数 fun 的地址。

因此,在此调用序列中

obj.Threading();

int Threading()
{
    fun();
}

为了调用函数 fun,在类 FD 的虚拟函数指针表中搜索指向函数 fun 的指针,并相应地使用 FD 类中提供的函数定义。 然后是 o

评论

0赞 463035818_is_not_an_ai 2/8/2023
vtable 是实现细节。当没有 vtable 时,OPs 代码也会产生相同的输出
0赞 Vlad from Moscow 2/8/2023
@463035818_is_not_a_number 但是在引擎盖下仍然使用了所描述的逻辑。
0赞 463035818_is_not_an_ai 2/8/2023
是的,这是一个实现细节;)。
0赞 Mark Ransom 2/8/2023
C++ 标准未指定必须使用 vtable。由于它被如此广泛地使用,因此了解它可能很好,但假设这是完成虚拟方法的唯一方法是错误的。