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

C++ 基类对象调用派生类函数(非虚拟)时会发生什么情况,c++,polymorphism,C++,Polymorphism,如果你觉得这个问题很傻,请原谅。我是一个C++新手,我在研究朗姆酒时间多态性。我想知道基类对象调用派生类函数(非虚拟)时会发生什么。例如,看看代码 class base { public: virtual void vfunc() {cout << "This is base's vfunc().\n";} }; class derived1 : public base { public: void vfunc() {cout <

如果你觉得这个问题很傻,请原谅。我是一个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;
}
如果有人能解释这两种情况下发生了什么(指针操作方面),我将非常感激


谢谢

这里的情况是有两个vtable,一个用于base,一个用于派生。在base的vtable中,有一个条目用于
vfunc()
,而在派生的vtable中,也有一个条目,诀窍是,当派生获取其父级的vtable时,它会查看它是否覆盖了其父级的任何虚拟方法,并且是。所以它取代了原来的版本,现在它指向了它自己的版本

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

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


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

在虚拟情况下,在运行时
p->vfunc()
告诉
p
转到类的类定义(内存中的任何部分)指针对象所属,并读取其vtable(或类似的替代实现)以确定要调用哪个函数

假设vtables如下所示:

base
的vtable:

----------------
vfunc | 0x2048
---------------- 
----------------
vfunc | 0x2096
---------------- 
derived1
的vtable:

----------------
vfunc | 0x2048
---------------- 
----------------
vfunc | 0x2096
---------------- 
然后根据vtables指向的位置调用vfunc的基本版本或派生版本

在非虚拟情况下,所有这些都不会发生,并且要调用的函数是由编译器在编译时设置的。在编译期间,编译器所能确定的是
p
属于“指向基的指针”类型,并将所有
p->vfunc()
调用更改为指向地址
0x2048