C++:虚函数和虚表详细总结

一、虚函数 (Virtual Functions)

1. 定义

虚函数是基类中使用 virtual 关键字声明的成员函数,支持动态多态性。通过基类指针或引用调用虚函数时,会根据实际对象类型选择调用相应的函数实现。

2. 声明和定义

  • 虚函数的声明

    class Base 
    {
    public:
        virtual void show(); // 声明虚函数
    };
    
  • 在派生类中重写虚函数

    class Derived : public Base 
    {
    public:
        void show() override; // 使用 override 关键字可选
    };
    

3. 动态绑定

通过基类指针或引用调用虚函数时,C++ 编译器会进行动态绑定,决定在运行时调用哪个版本的函数。

Base* b = new Derived();
b->show(); // 输出:Derived class show() called.
//动态绑定

4. 纯虚函数

  • 定义:没有实现的虚函数,用于定义接口,使用 = 0 声明。
class AbstractBase 
{
public:
    virtual void show() = 0; // 纯虚函数
};

包含纯虚函数的类称为抽象类,无法实例化。

二、虚表 (Vtable)

1. 定义

虚表是由编译器为每个包含虚函数的类生成的结构,包含该类所有虚函数的指针。

2. 虚表的结构

  • 每个包含虚函数的类都有一个虚表,当调用的类为虚类时,会访问这个表,寻找具体实现。
  • 如果子类未重写某个虚函数,则虚表中会指向父类的实现。
  • 如果子类重写了某个虚函数,则虚表中会指向该类的实现.

3. 虚表的示例

class Base 
{
public:
    virtual void show() { std::cout << "Base class show()" << std::endl; }
};

class Derived : public Base {
    // No override
};

int main() {
    Base* b = new Derived();
    b->show(); // Calls Base::show()
    delete b;
    return 0;
}
4. 内存布局
  • Base 的虚表:
    [0] -> Base::show()
    
  • Derived 的虚表(未重写的情况下):
    [0] -> Base::show() // 指向父类的实现
    

5. 虚指针 (vptr)

  • 每个对象实例中都有一个虚指针,指向该对象所属类的虚表。
  • 虚指针通常是对象的第一个成员。

三、虚函数的特点

  1. 动态多态性:通过基类指针或引用调用子类的实现,支持在运行时决定函数调用。

  2. 基类指针和引用:允许使用基类类型来引用和操作派生类对象。

  3. 封装和保护:基类不需要了解具体的派生类实现,增强了代码的模块化和可维护性。

  4. 构造与析构的特殊性:构造时不调用派生类的虚函数,析构时确保派生类析构函数被调用。

  5. 性能开销

    • 空间开销:每个类需要存储虚表和每个对象需要一个虚指针。
    • 时间开销:调用虚函数时需要通过虚表查找函数地址,相比于普通函数调用有额外的开销。

四、虚函数的使用场景

  1. 实现接口:通过纯虚函数定义接口类。

  2. 多态行为:在需要不同对象间以相同方式处理时(如图形、游戏对象等)。

  3. 框架设计:在库或框架设计中,通过虚函数提供扩展点,让用户自定义行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云璃丶夢紡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值