讲师中心 微信公众号
AI工具推荐 视频效率加速

C++多态是怎么实现的 虚函数与动态绑定机制

夜杰同学_9546

夜杰同学_9546

发布时间:2025-07-18 11:12:02

|

369人浏览过

|

来源于php中文网

原创

c++多态性通过虚函数和动态绑定机制实现。1. 虚函数允许子类重写父类的方法,动态绑定在运行时确定调用哪个版本的函数;2. 虚函数表(vtable)是包含虚函数地址的函数指针数组,每个对象通过虚函数指针(vptr)指向其类的vtable,从而在运行时找到实际调用的函数;3. 基类析构函数应声明为虚函数,以确保通过基类指针删除派生类对象时能正确调用派生类和基类的析构函数,避免内存泄漏;4. 纯虚函数没有具体实现,包含纯虚函数的类为抽象类,不能被实例化,只能被继承;5. 动态绑定带来运行时函数地址查找的性能开销,虽比静态绑定慢,但通常可接受,必要时可用静态绑定或模板优化性能。

C++多态是怎么实现的 虚函数与动态绑定机制

C++多态性通过虚函数和动态绑定机制实现。简单来说,虚函数允许子类重写父类的方法,而动态绑定则是在运行时确定调用哪个版本的函数。

C++多态是怎么实现的 虚函数与动态绑定机制

虚函数与动态绑定机制

C++多态是怎么实现的 虚函数与动态绑定机制

虚函数表(Vtable)和虚函数指针(Vptr)

每个包含虚函数的类都会有一个虚函数表(Vtable),它是一个函数指针数组,存储着该类所有虚函数的地址。类的每个对象都会包含一个虚函数指针(Vptr),指向该类的Vtable。当通过指针或引用调用虚函数时,编译器会通过Vptr找到Vtable,然后根据函数在Vtable中的偏移量找到实际要调用的函数地址。

立即学习“C++免费学习笔记(深入)”;

这种机制的关键在于,Vtable是在编译时确定的,而Vptr是在运行时确定的。因此,即使在编译时不知道对象的具体类型,也可以在运行时正确地调用相应的虚函数。

C++多态是怎么实现的 虚函数与动态绑定机制

举个例子:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
class Animal {
public:
    virtual void makeSound() {
        std::cout << "Generic animal sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() override {
        std::cout << "Woof!" << std::endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        std::cout << "Meow!" << std::endl;
    }
};

int main() {
    Animal* animal1 = new Animal();
    Animal* animal2 = new Dog();
    Animal* animal3 = new Cat();

    animal1->makeSound(); // 输出 "Generic animal sound"
    animal2->makeSound(); // 输出 "Woof!"
    animal3->makeSound(); // 输出 "Meow!"

    delete animal1;
    delete animal2;
    delete animal3;

    return 0;
}

在这个例子中,Animal 类声明了一个虚函数 makeSound()。Dog 和 Cat 类都重写了这个函数。在 main() 函数中,我们创建了指向 Animal 对象的指针,但实际上它们指向的是 Animal、Dog 和 Cat 类型的对象。当调用 makeSound() 函数时,由于它是虚函数,所以会根据对象的实际类型来调用相应的函数。这就是动态绑定的体现。

为什么需要虚析构函数?

如果基类的析构函数不是虚函数,那么通过基类指针删除派生类对象时,只会调用基类的析构函数,而不会调用派生类的析构函数,这会导致内存泄漏。

考虑以下代码:

class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    ~Base() { std::cout << "Base destructor" << std::endl; }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor" << std::endl;
        data = new int[10];
    }
    ~Derived() {
        std::cout << "Derived destructor" << std::endl;
        delete[] data;
    }
private:
    int* data;
};

int main() {
    Base* b = new Derived();
    delete b; // 只调用Base的析构函数,导致内存泄漏
    return 0;
}

如果将 Base 类的析构函数声明为虚函数,那么通过基类指针删除派生类对象时,会先调用派生类的析构函数,然后再调用基类的析构函数,从而避免内存泄漏。

class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    virtual ~Base() { std::cout << "Base destructor" << std::endl; }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor" << std::endl;
        data = new int[10];
    }
    ~Derived() {
        std::cout << "Derived destructor" << std::endl;
        delete[] data;
    }
private:
    int* data;
};

int main() {
    Base* b = new Derived();
    delete b; // 先调用Derived的析构函数,再调用Base的析构函数
    return 0;
}

纯虚函数和抽象类

纯虚函数是在基类中声明的虚函数,它没有具体的实现。包含纯虚函数的类称为抽象类。抽象类不能被实例化,只能被继承。

class Shape {
public:
    virtual double area() = 0; // 纯虚函数
};

class Circle : public Shape {
public:
    Circle(double r) : radius(r) {}
    double area() override { return 3.14159 * radius * radius; }
private:
    double radius;
};

int main() {
    // Shape s; // 错误:不能实例化抽象类
    Circle c(5);
    std::cout << "Area: " << c.area() << std::endl;
    return 0;
}

在这个例子中,Shape 类是一个抽象类,因为它包含一个纯虚函数 area()。Circle 类继承了 Shape 类,并实现了 area() 函数。

动态绑定带来的性能开销

动态绑定需要在运行时查找函数地址,这会带来一定的性能开销。与静态绑定相比,虚函数调用通常会慢一些。然而,这种开销通常是可以接受的,因为动态绑定带来的灵活性和可扩展性往往更重要。在对性能有严格要求的场景下,可以考虑使用静态绑定或模板等技术来避免动态绑定带来的开销。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

相关专题

更多
java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

375

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

375

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

375

2025.11.27

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

379

2026.04.23

Docker Desktop怎么设置端口映射
Docker Desktop怎么设置端口映射

本专题聚焦Docker Desktop容器端口映射与访问配置,整理从创建容器、设置端口绑定到验证本地服务访问的操作流程。针对端口被占用、映射配置错误、容器服务无法访问等情况,也提供相应的检查方向,方便用户完成端口配置。

0

2026.11.03

Docker Desktop镜像构建教程
Docker Desktop镜像构建教程

想使用Docker Desktop将本地项目构建成Docker镜像?本专题围绕镜像构建的实际操作展开,介绍Dockerfile编写、构建命令使用、镜像标签设置和构建日志查看等内容,同时整理镜像无法生成、依赖安装失败及构建缓存异常等问题的排查思路。

0

2026.11.03

Docker Desktop容器创建指南
Docker Desktop容器创建指南

本专题聚焦Docker Desktop容器创建与运行配置,介绍通过本地镜像或远程镜像创建容器的方法,以及容器启动、终端访问、日志查看和基础管理等操作。针对端口冲突、参数配置不当、容器无法启动等情况,也整理了相应的排查方向。

0

2026.11.03

Tailwind CSS 如何制作导航栏和卡片
Tailwind CSS 如何制作导航栏和卡片

用 Tailwind CSS 制作导航栏和卡片,可先搭建语义化结构,再组合 Flex、Grid、间距、圆角与阴影类。这里整理横向导航、移动端菜单、卡片网格及悬停效果的相关文章,帮助你把常见页面组件做得清晰且适配不同屏幕。

20

2026.11.03

Tailwind CSS 响应式布局怎么写
Tailwind CSS 响应式布局怎么写

Tailwind CSS 响应式布局通常从移动端样式写起,再用 sm、md、lg 等前缀调整不同屏幕宽度下的网格、间距和导航。本专题整理断点配置、Grid 与 Flex 自适应布局及常见溢出问题,帮助你逐步完成多设备适配。

0

2026.11.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go语言教程-全程干货无废话
Go语言教程-全程干货无废话

共100课时 | 18.1万人学习

第三期培训_PHP开发
第三期培训_PHP开发

共116课时 | 33万人学习

PHP零基础通关宝典
PHP零基础通关宝典

共78课时 | 13.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn