C++虚函数有什么用 C++多态实现原理与代码演示【进阶】

发布时间 - 2026-01-29 00:00:00    点击率:
虚函数实现运行时多态,通过vtable和vptr支持动态绑定;非静态成员函数可声明为虚,构造函数不可,析构函数应为virtual以防资源泄漏;纯虚函数使类抽象化。

虚函数是用来让基类指针/引用调用子类重写函数的

没有 virtual,编译器在编译时就决定调用哪个函数(静态绑定);加上 virtual 后,实际调用哪个函数由运行时对象的真实类型决定(动态绑定)。这是实现运行时多态的唯一语言机制。

常见错误现象:Base* p = new Derived(); p->func(); 调用的却是 Base::func() —— 很可能因为 func() 在基类里没声明为 virtual

  • 只有非静态成员函数能是虚函数;构造函数不能是虚函数,析构函数建议声明为 virtual
  • 虚函数可以被继承、被重写(override),但重写时签名必须完全一致(C++11 起推荐加 override 关键字显式声明)
  • 纯虚函数(virtual void func() = 0;)让类变成抽象类,不能实例化,强制子类实现

虚函数表(vtable)和虚函数指针(vptr)是多态的底层支撑

C++ 标准不规定实现细节,但主流编译器(GCC、Clang、MSVC)都用「每个类一张虚函数表 + 每个对象一个虚函数指针」的方式。vtable 是函数指针数组,存着该类所有虚函数的地址;vptr 是对象内存布局开头的一个隐式指针,指向其所属类的 vtable。

使用场景:调试时查看对象内存布局、理解多继承下虚函数调用开销、排查虚函数未生效问题。

性能影响:virtual 函数调用比普通函数多一次间接寻址(通过 vptr 找 vtable,再索引函数指针),但现代 CPU 分支预测和缓存优化后开销极小;真正代价在于禁止内联(除非编译器能确定具体类型)。

示例(简化示意):

struct Base {
    virtual void f() { }
    virtual void g() { }
};
struct Derived

: Base { void f() override { } // 覆盖 Base::f }; // sizeof(Derived) 通常比 sizeof(Base) 大?不一定——vptr 通常只占一个指针大小,且 Base 和 Derived 共享同一份 vptr 偏移

为什么父类析构函数要声明为 virtual

否则 delete 基类指针时,只会调用基类析构函数,子类析构逻辑被跳过 —— 这是资源泄漏(如文件句柄、堆内存、锁)的常见根源。

错误代码:

class Base {
public:
    ~Base() { cout << "Base dtor\n"; }
};
class Derived : public Base {
    int* data;
public:
    Derived() { data = new int[100]; }
    ~Derived() { delete[] data; cout << "Derived dtor\n"; }
};
Base* p = new Derived();
delete p; // 只输出 "Base dtor",data 泄漏

修复方式:把 Base::~Base() 改成 virtual ~Base()

  • 只要类设计为被继承(尤其有虚函数),就该把析构函数设为 virtual
  • 如果类明确禁止继承,可加 final;若既不继承也不多态,析构函数无需 virtual
  • std::unique_ptr 同样受此规则约束 —— 它的默认删除器也依赖虚析构

虚函数和 override / final 的配合容易踩坑

不加 override 时,子类函数名拼错、参数类型不匹配(如 int vs const int&)、const 限定不一致,都会导致“看似重写实则新增一个重载函数”,多态失效却无编译错误。

示例:

struct Base {
    virtual void process(int x);
};
struct Derived : Base {
    void process(int x) const override; // 错!const 不匹配,编译失败(有 override)
    void process(int x) override;         // 对
    void process(double x) override;      // 错!参数类型不同,不是重写,编译失败
};
  • 始终对重写函数加 override —— 编译器会严格校验是否真能覆盖基类虚函数
  • final 可用于函数(禁止进一步重写)或类(禁止继承),例如 virtual void f() final;
  • 虚函数不能是 staticfriendtemplate(但虚函数模板特化可以存在)

虚函数机制本身简单,但它的行为高度依赖编译器对继承关系、函数签名、内存布局的精确理解;一旦某个环节出偏差(比如忘记 virtual、签名差一个 const、多继承下 vtable 偏移错乱),多态就静默失效,而这类 bug 往往在运行时才暴露,且难以追踪。


# c++  # 为什么  # Static  # 多态  # 成员函数  # 父类  # 子类  # 构造函数  # 析构函数  # const  # 引用调用  # int  # void  # 指针  # 继承  # 多继承  # 重载函数  # 虚函数  # 纯虚函数  #   # 函数模板  # delete  # 对象  # bug  # 重写  # 这是  # 绑定  # 不匹配  # 特化  # 也不  # 却是  # 句柄 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  laravel怎么配置和使用PHP-FPM来优化性能_laravel PHP-FPM配置与性能优化方法  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  Laravel如何实现本地化和多语言支持?(i18n教程)  WEB开发之注册页面验证码倒计时代码的实现  绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信  ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集  北京网站制作公司哪家好一点,北京租房网站有哪些?  Laravel怎么使用artisan命令缓存配置和视图  详解CentOS6.5 安装 MySQL5.1.71的方法  HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  如何用好域名打造高点击率的自主建站?  长沙企业网站制作哪家好,长沙水业集团官方网站?  Laravel如何使用Gate和Policy进行授权?(权限控制)  Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势  INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】  Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】  教你用AI将一段旋律扩展成一首完整的曲子  Laravel如何自定义错误页面(404, 500)?(代码示例)  湖南网站制作公司,湖南上善若水科技有限公司做什么的?  JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)  Python并发异常传播_错误处理解析【教程】  Win11怎么设置虚拟桌面 Win11新建多桌面切换操作【技巧】  如何在宝塔面板中创建新站点?  如何在沈阳梯子盘古建站优化SEO排名与功能模块?  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】  HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】  Laravel如何生成和使用数据填充?(Seeder和Factory示例)  如何在Tomcat中配置并部署网站项目?  Laravel Session怎么存储_Laravel Session驱动配置详解  如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  如何用PHP快速搭建高效网站?分步指南  b2c电商网站制作流程,b2c水平综合的电商平台?  Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境  如何在阿里云虚拟主机上快速搭建个人网站?  Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议  如何快速打造个性化非模板自助建站?  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  php做exe能调用系统命令吗_执行cmd指令实现方式【详解】  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  网站制作企业,网站的banner和导航栏是指什么?  香港服务器建站指南:外贸独立站搭建与跨境电商配置流程  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  Laravel Fortify是什么,和Jetstream有什么关系  QQ浏览器网页版登录入口 个人中心在线进入  高防服务器租用指南:配置选择与快速部署攻略