如果在编译时间中创建虚拟表,那么为什么我们将其称为运行时间多态性

If virtual table is created in compile time, then why do we call this as a run time polymorphism?

本文关键字:我们将 为什么 多态性 运行时间 时间 编译 创建 虚拟 如果      更新时间:2023-10-16

作为编译时间创建虚拟表,为什么我们将其称为C 中的运行时间多态性?

P>由于查找在运行时发生。

在典型的实现中,每个类都有一个虚拟表,该表在编译时已知。

在运行时,BaseClass *类型的指针可能指向一个类型为BaseClass的对象,或者指向其类型为DerivedClass的对象的基类子对象,其中BaseClassDerivedClass的基础。引用也是如此。

在前一种情况下,在BaseClass的VTable中抬高了一个虚拟呼叫。在后一种情况下,在DerivedClass的VTable中抬高了一个虚拟呼叫。由于呼叫站点直到在运行时实际执行呼叫之前,呼叫站点才"知道"哪个函数,这称为动态或运行时多态性。

再次在典型的实现中,它发现使用哪种VTable的方式是,具有一个或多个虚拟函数类型的对象包含一个"隐藏"的附加字段,该字段指向其完整类型的可vtable。那是简单的继承。多重和虚拟继承增加并发症,但原理是相同的,该对象为应使用的任何VTable提供了指针。

将此与非虚拟呼叫进行比较,在此中,合并不需要使用任何VTable或知道完整对象的类型。它根据指针或参考的类型选择功能。

虚拟表是无关紧要的。C 中的运行时多态性表示:

struct B {
    virtual void f() { std::cout << "In Bn"; }
};
struct D1 : B {
    virtual void f() { std::cout << "In D1n"; }
};
struct D2 : b {
    virtual void f() { std::cout << "In D2n"; }
};
B *bp = new B;
bp->f();   // calls B::f
B *bp1 = new D1;
bp1->f();  // calls D1::f
B *bp2 = new D2;
bp2->f();  // calls D2::f

即使所有三个指针都具有B*类型,对f()的呼叫的行为取决于指针指向的对象的运行时类型。

<正如您所说,每个类的虚拟功能表(和其他多态信息)是在编译时生成的。>

每个对象都包含一个指向其动态类型的正确表的指针。该指针在创建对象时在运行时初始化,并在运行时使用以选择要调用的正确虚拟函数。这就是为什么它称为运行时多态性。

虚拟表是在编译期间创建但在运行时使用的。

虚拟表是C 类型和其他一些OO语言的类型的运行时表示的元素。它用于动态调度虚拟方法调用。换句话说,这是C 动态多态性特征的实现细节

构造该表的时间与调度方案无关,该计划定义了多态性是静态的还是动态的。

您必须必须简要了解什么是运行时多态性以及其工作原理。

如果您有这样的类层次结构:

class Animal
{
    ...
    virtual void sayHello() {
        cout << "hello" << endl;
    }
};
class Dog : public Animal
{
    ...
    /*virtual*/ void sayHello() {
        cout << "woof!" << endl;
    }
};

并在Dog实例上调用方法,您希望能够调用Dog的(虚拟)覆盖方法,而不是Animal。我想你知道我们为什么想要这个,所以我不想进一步解释。

但是,在运行时我们怎么知道Animal*实际上是Dog*?问题是,我们不必知道是什么,我们只需要知道要调用哪些功能,或者更好地说,哪个功能 pointer pointer /em>致电。虚拟函数的所有功能指针都存储在每个类的虚拟表中。您可以将其想象为"指南",以拨打哪个代码,以实现哪种虚拟函数,这取决于

此虚拟表是在编译时间内创建的(编译器将"指南"写入可执行文件中),每个实例指向一个可用的虚拟表之一。因此,如果您说Dog *dog = new Dog,则指向狗的虚拟表。诸如dog->sayHello()之类的调用将尚未指定的类的虚拟呼叫汇编为虚拟函数sayHello ...

然后,在运行时 dog->sayHello()之类的调用将首先查找存储在对象中的混凝土虚拟表(代码不知道它是狗,只有它是动物)并找到方法Dog::sayHello()的功能指针。

要回答您的问题,此机制称为运行时多态性,因为我们可以调用过载该指针的方法on)虽然在运行时做出决定。您可以调用对话编译时间多态性编译器可以知道混凝土类型的对象,例如Dog dog; dog.sayHello()中的对象类型。

虽然在编译时创建V-table时,当编译以下代码时,编译器不知道将调用哪个函数:

struct A {
    virtual void f() { cout << "A::f" << endl;}
};
struct B : public A {
    void f() { cout << "B::f" << endl;}
};
int main() {
    A* b = new B();
    b->f(); // prints "B::f", chosen at runtime
}

so,尽管对象在编译时间和运行时间之间不变,但方法B :: F仅在运行时选择,因为编译器不知道对象的动态类型(哪个确定要调用的方法)。

相关文章: