<c++>虚函数的运行原理及其流程

当在C++中发生多态时,整个运行流程可以分解为以下步骤:

1. 定义基类和派生类

首先,我们定义一个基类和一个或多个派生类。基类中至少有一个虚函数,派生类会重写这个虚函数。

class Base {
public:
    virtual void show() {
        std::cout << "Base class show function called." << std::endl;
    }
};
class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived class show function called." << std::endl;
    }
};

2. 创建派生类对象

接下来,我们创建一个派生类的对象。

Derived d;

3. 对象内存布局

当派生类对象 d 被创建时,它的内存布局包括:

  • 基类的成员变量(如果有)
  • 虚函数指针(vptr),指向派生类的虚函数表(vtable)

4. 虚函数表(vtable)

虚函数表是一个函数指针数组,它包含基类和派生类中所有虚函数的指针。对于派生类,它的vtable通常开始时会包含基类vtable的副本,然后是派生类新增或重写的虚函数指针。

5. 发生多态

现在,我们通过基类指针或引用来调用虚函数。

Base* bptr = &d;
bptr->show();

以下是发生多态时的详细步骤:

步骤 1: 指针或引用赋值

bptr 被赋值为派生类对象 d 的地址。

步骤 2: 调用虚函数

通过基类指针 bptr 调用 show 函数。

步骤 3: 解析虚函数调用

在运行时,C++解析器查看 bptr 指向的对象的虚函数指针(vptr)。

步骤 4: 查找虚函数表

解析器通过vptr找到派生类的虚函数表(vtable)。

步骤 5: 调用正确的函数

解析器在vtable中查找 show 函数的指针,并调用它。由于 show 在派生类中被重写,所以调用的是 Derived::show

步骤 6: 执行派生类的函数

Derived::show 被执行,输出相应的信息。

总结

整个多态的运行流程可以概括为:

  1. 创建派生类对象,该对象包含一个指向其vtable的vptr。
  2. 通过基类指针或引用调用虚函数。
  3. 在运行时,通过对象的vptr找到正确的vtable。
  4. 从vtable中获取正确的虚函数指针并调用函数。
  5. 执行派生类中重写的函数。
    这个过程确保了即使是通过基类类型的指针或引用调用函数,也能够调用到派生类中重写的函数实现,从而实现了多态。

补充

只有当类被实例化为对象时,才会为该对象分配一个虚函数表指针(vptr)。虚函数表本身是类的一部分,它在程序编译时就已经确定,并且是静态存储的,但是每个对象在创建时才会被分配一个指向其类虚函数表的vptr。
这里有几个关键点:

  1. 类的虚函数表:每个包含虚函数的类都有一个虚函数表,这个表是类的一部分,而不是对象的一部分。它包含了类中所有虚函数的指针。
  2. 对象的虚函数表指针:当类的实例被创建时,对象的内存布局中会包含一个vptr,这个指针指向其类的虚函数表。
  3. 多态行为:由于每个对象都有一个vptr,多态行为得以实现。当通过基类指针或引用调用虚函数时,实际上是通过对象的vptr找到正确的虚函数表,并调用相应的函数。
    下面是一个简单的示例来说明这一点:
class Base {
public:
    virtual void func() { std::cout << "Base::func" << std::endl; }
};
class Derived : public Base {
public:
    void func() override { std::cout << "Derived::func" << std::endl; }
};
int main() {
    Base b; // 创建基类对象,b有一个vptr指向Base的虚函数表
    Derived d; // 创建派生类对象,d有一个vptr指向Derived的虚函数表
    return 0;
}

在这个例子中,bd 对象都有各自的vptr,但它们指向不同的虚函数表。b 的vptr指向Base类的虚函数表,而d的vptr指向Derived类的虚函数表。
如果没有创建类的实例,那么虚函数表仍然存在,但是没有具体的对象来持有指向这些表的vptr。因此,虚函数表是在类层面定义的,而vptr是在对象实例化时分配的。

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值