news 2026/5/1 4:50:02

虚函数详解(一)—— 虚函数基本原理与单继承

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
虚函数详解(一)—— 虚函数基本原理与单继承

前言

        在C++的众多特性中,虚函数是实现运行时多态的基石。理解虚函数的工作原理,对于写出正确、高效的面向对象程序至关重要。本系列将从底层机制出发,深入剖析虚函数的方方面面。作为开篇,我们先聚焦于最基础也最核心的部分:虚函数的基本原理,以及它在单继承体系下的行为。

一、从静态绑定到动态绑定

        在C++中,当我们通过对象、指针或引用来调用一个成员函数时,编译器需要决定实际执行哪个函数,这个过程称为绑定。

1.1 静态绑定        

       对于非虚函数,绑定发生在编译期:

class Base { public:     void show() { std::cout << "Base::show()" << std::endl; } }; class Derived : public Base { public:     void show() { std::cout << "Derived::show()" << std::endl; } }; int main() {     Derived d;     Base* ptr = &d;     ptr->show();   // 输出:Base::show() }

        虽然 `ptr` 实际指向一个 `Derived` 对象,但因为 `show` 不是虚函数,编译器仅根据指针的静态类型(`Base*`)来决定调用 `Base::show`。这种“指鹿为马”的行为显然不符合多态的预期,解决方案正是虚函数。

1.2 动态绑定(虚函数)       

         只需在基类函数前加上 `virtual` 关键字:
 

class Base { public:     virtual void show() { std::cout << "Base::show()" << std::endl; } }; class Derived : public Base { public:     void show() override { std::cout << "Derived::show()" << std::endl; } }; // ptr->show(); 将会输出:Derived::show()

        这样一来,调用的函数不再由指针的静态类型决定,而是由指针所指对象的**真实类型**在运行时决定,这就是动态绑定。支撑这一机制的秘密武器,便是**虚函数表(vtable)** 与**虚函数指针(vptr)。

二、虚函数表和虚函数指针的内存布局

2.1 什么是虚函数表

        编译器为每个包含虚函数的类(或继承自包含虚函数的类)生成一张表,表中存放了该类所有虚函数的实际入口地址。这张表就是虚函数表(vtable)。注意,虚函数表是**类级别**的,同一个类的所有实例共享同一张虚函数表。

2.2 虚函数指针

        每个包含虚函数的类的对象,内部会隐式地多出一个指针成员,指向它所属类的虚函数表。这个指针就是虚函数指针(vptr),通常位于对象内存布局的最前端(具体位置依赖编译器实现,但绝大多数编译器如此)。vptr 是**对象级别**的,每个对象拥有自己的 vptr,虽然它们指向的可能是同一张 vtable。        

        我们用一段代码来验证(以典型的 64 位编译器为例):

#include <iostream> class Base {     int data; public:     virtual void func1() { std::cout << "Base::func1()\n"; }     virtual void func2() { std::cout << "Base::func2()\n"; } }; int main() {     Base b;     std::cout << "sizeof(Base): " << sizeof(b) << std::endl; }

        输出可能是:`sizeof(Base): 16`(其中 8 字节是 vptr,4 字节为 `int data`,还有 4 字节因对齐而填充)。也就是说,一个空壳的 `Base` 对象内部有一个无形的指针,指向基类的虚函数表。

2.3 虚函数表的结构

&

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 4:46:03

Leptos包大小优化终极指南:如何将WASM文件缩减至最小

Leptos包大小优化终极指南&#xff1a;如何将WASM文件缩减至最小 【免费下载链接】leptos Build fast web applications with Rust. 项目地址: https://gitcode.com/GitHub_Trending/le/leptos Leptos是一个使用Rust构建快速Web应用的框架&#xff0c;通过WebAssembly&a…

作者头像 李华
网站建设 2026/5/1 4:45:28

10个高效技巧:如何使用go-github库快速验证GitHub仓库模板API

10个高效技巧&#xff1a;如何使用go-github库快速验证GitHub仓库模板API 【免费下载链接】go-github Go library for accessing the GitHub v3 API 项目地址: https://gitcode.com/GitHub_Trending/go/go-github go-github是一个功能强大的Go语言库&#xff0c;专门用于…

作者头像 李华
网站建设 2026/5/1 4:42:08

搞Web自动化测试/爬虫必看:如何为Selenium固定Chrome驱动版本(附历史版本下载与匹配方法)

Web自动化测试与爬虫工程中的Chrome驱动版本锁定实战指南 当你在凌晨三点调试自动化测试脚本时&#xff0c;突然发现所有用例集体报错——这往往是Chrome自动更新后驱动不兼容导致的"午夜惊魂"。作为经历过数十次类似场景的老兵&#xff0c;我深刻理解版本不一致对自…

作者头像 李华
网站建设 2026/5/1 4:37:46

SUSI.AI技能创建教程:从零开始开发智能对话

SUSI.AI技能创建教程&#xff1a;从零开始开发智能对话 【免费下载链接】susi.ai SUSI.AI Web Client https://susi.ai 项目地址: https://gitcode.com/gh_mirrors/su/susi.ai SUSI.AI是一个开源的智能对话平台&#xff0c;让你能够轻松创建自己的AI技能。本教程将引导你…

作者头像 李华