C++虚函数、虚析构的那些事儿!

1、静态绑定和动态绑定

  • 静态绑定

    • 在编译时确定调用的函数。

    • 适用于非虚函数(包括非虚析构函数)。

    • 编译器根据指针或引用的静态类型(声明类型)来决定调用哪个函数。

  • 动态绑定

    • 在运行时确定调用的函数。

    • 适用于虚函数(包括虚析构函数)。

    • 编译器根据对象的动态类型(实际类型)来决定调用哪个函数。

2、子类的“虚表”是如何产生的?

  • 多态:

    • 满足条件:①有继承关系;②子类重写父类中的虚函数

    • 使用条件:父类指针或引用指向子类对象

       当一个类中包含有虚函数(被virtual修饰的成员函数)时,编译器在编译阶段会为该类创建一张表叫做“虚函数表”,简称“虚表”,存储当前类中的虚函数指针,虚表本质上是一个函数指针数组。

       每个对象内部都有一个隐藏的虚表指针(vptr),指向其所属类的虚表。vptr 在对象构造时被初始化,指向正确的虚表。

  • 子类虚表的产生:

    • 子类继承父类的虚表:子类会拷贝一份父类的虚表。

    • 子类覆盖重写的虚函数:如果子类重写了父类的虚函数,子类的虚表中对应的函数指针会被替换为子类的函数地址。重写:函数的返回值类型、函数名、形参列表类型都相同。

    • 子类添加额外的虚函数:子类新增的虚函数会依次添加在虚表的末尾。

    • 非虚函数不会被放入虚表:只有虚函数会被放入虚表,非虚函数的调用是静态绑定的。

       虚表指针(vptr)属于对象,存储在对象的内存布局中。虚表(vtable):属于类,存储在程序的常量区(只读数据段)。

        以下是一个示例,展示 vptr 和虚表的关系:

3、关键字final和override

  • final 可以用于类或虚函数:

    • 用于类时,表示该类不能被继承,为最终类。

    • 用于父类虚函数时,表示该函数不能在子类中被重写。

  • override

    • 用于显式标记子类中的函数是重写父类的虚函数。

    • 如果标记了 override,但实际没有重写父类的虚函数,编译器会报错。

4、协变—一种特殊的返回值类型规则

  • 协变的基本规则

    • 返回类型必须是指针或引用。

    • 子类的返回类型必须是父类返回类型的子类。

5、虚析构与纯虚析构

        虚析构函数的主要作用是确保通过父类指针删除子类对象时,能够正确调用子类的析构函数,从而避免资源泄漏。子类没有显式定义析构函数,编译器也会生成一个默认的析构函数,并覆盖父类的析构函数。若子类中有属性开辟到堆区,需要显式定义析构函数。

6、父类析构函数怎么被调用的?

  • 子类的析构函数 Derived::~Derived 会先执行子类的析构逻辑。

  • 在 Derived::~Derived 执行完毕后,编译器会自动插入代码调用父类的析构函数 Base::~Base。这个过程是隐式的,不需要程序员显式编写。

调整心态,脚步不停下,就是在进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值