当基类对象调用派生类函数(非虚拟)时会发生什么

时间:2012-09-22 16:21:53

标签: c++ polymorphism

如果这个问题对你很愚蠢,请原谅我。我是c ++的新手,我正在研究朗姆酒时间多态性。我想知道当基类对象调用派生类函数(非虚拟)时会发生什么。例如,查看代码

class base {
    public:
        virtual void vfunc() {cout << "This is base's vfunc().\n";}
};

class derived1 : public base {
    public:
        void vfunc() {cout << "This is derived1's vfunc().\n";}
};

int main()
{
    base *p, b;
    derived1 d1;

    p = &b;
    p->vfunc();

    p = &d1;
    p->vfunc();

    return 0;
}

我得到了所需的输出,然后我从基类中删除了虚拟关键字,当我运行程序时,输出是

This is base's vfunc().
This is base's vfunc().

如果有人解释在两种情况下发生的事情(就指针操纵而言),我将非常感激

由于

2 个答案:

答案 0 :(得分:2)

在虚拟情况下,在运行时p->vfunc()告诉p转到类的类定义(它的任何部分在内存中)指向者属于,并读取其vtable(或一些类似的替代实现)来确定要调用的函数。

假设vtable如下所示:

base的vtable:

----------------
vfunc | 0x2048
---------------- 

derived1的vtable:

----------------
vfunc | 0x2096
---------------- 

然后根据vtable指向的位置调用vfunc的基本版本或派生版本。

在非虚拟情况下,没有发生这种情况,并且编译器在编译时将调用函数。在编译期间,所有编译器都可以确定p是'指向基址的指针'类型,并将所有p->vfunc()调用更改为指向地址0x2048

答案 1 :(得分:1)

这里发生的是有两个vtable,一个用于基础,一个用于派生。在base的vtable中你有vfunc()的一个条目,在derived的vtable中也有一个条目,诀窍是当派生它的父级的vtable时它看起来是否覆盖它的任何父的虚方法而且它是。所以它取代了那里的东西,现在它指向它自己的版本。

换句话说,当您通过类型为base的实例调用vfunc()时,检查基本vtable,其中包含指向base vfunc()的指针。当您通过派生实例调用它时,您会找到指向派生的vfunc()

的指针

如果删除virtual关键字,编译器不再寻找虚函数,而是基于对象的运行时类型,而是基于它的静态/编译时类型。

换句话说,如果没有virtual关键字,编译器会查看base的指针类型,因此每次调用基本版本。