news 2026/5/30 0:38:40

虚函数/纯虚数及抽象类笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
虚函数/纯虚数及抽象类笔记

虚函数简单介绍理解

C++提供的新机制,虚函数允许函数调用与函数体的匹配在运行时才确定,是一种动态绑定机制。

正常来说,通过基类引用或指针所能看到的是一个基类对象,派生类中的成员对于基类引用或指针来说是不可见的,无法通过基类的指针或引用指向派生类。

举例:

class Base_demo { public: void demo() { cout << "这是基类Base" << endl; } }; class Derived_demo :public Base_demo { public: void demo() { cout << "这是派生类Derived" << endl; } }; int main() { Base_demo b1, *b2; Derived_demo d1 ; b2 = &b1; b2->demo();//这是基类Base b2 = &d1; b2->demo();//这是基类Base return 0; }

我们想通过基类引用或指针来访问派生类的成员,就得使用本章的主题虚函数——virtual,将基类的Print说明为虚函数形式。这样就可以通过基类引用或指针来访问派生类:

class Base_demo { public: virtual void demo() {//在此使用虚函数 cout << "这是基类Base" << endl; } }; class Derived_demo :public Base_demo { public: void demo() { cout << "这是派生类Derived" << endl; } }; int main() { Base_demo b1, *b2; Derived_demo d1 ; b2 = &b1; b2->demo();//这是基类Base b2 = &d1; b2->demo();//这是派生类Derived return 0; }

为了更好体现虚函数在运行时才确定,下面我将使用if进行判断运行;

class Base_demo { public: virtual void Demo() { cout << "这是基类Base" << endl; } }; class Derived_demo :public Base_demo { public: void Demo() { cout << "这是派生类Derived" << endl; } }; class if_demo{ public: void Demo(Base_demo& b1, Derived_demo& d1, Base_demo*& b2) { int condition; cin >> condition; if (1 == condition) b2 = &b1; else b2 = &d1; } }; int main() { Base_demo b1, * b2; Derived_demo d1; if_demo i1; i1.Demo(b1, d1, b2); b2->Demo(); return 0; }

如上,Demo的调用依赖于用户输入的condition值,而非在编译阶段就确定好谁调用Demo。

虚函数概念理解

在基类中,用virtual关键字声明的成员函数即是虚函数。并且,虚函数可以在一个或者多个公有派生类中被定义但是要求虚函数的原型必须完全相同。

否则原型不同,如只函数名相同,会被编译器定义为函数重载,从而丢失虚函数特性。仅返回类型不同,其他相同。C++编译器认为这种情况是不允许的。

意义:基类使用虚函数提供一个接口,但派生类可以定义自己的实现版本。调用的解释依赖于它的对象类型,这就实现了“一个接口,多种语义”的概念。

注意虚函数的限制条件:

1.不能将虚函数说明为全局函数。

2.不能将虚函数说明为静态成员函数。

3.不能将虚函数说明为友元函数。

4.虚函数必须是类的非静态成员函数。

class Base { public: // 错误:构造函数不能是virtual virtual Base() { } };

原因:

虚函数的调用依赖对象的虚指针(VPTR)和虚函数表(VTABLE),但:

1.VPTR 是在构造函数中初始化的:对象的 VPTR 是由类的构造函数自动设置的(构造函数执行时,才会把 VPTR 指向当前类的 VTABLE);
2.构造函数执行时,对象还没完全创建:构造函数是用来 “创建对象” 的,执行构造函数的那一刻,对象的内存刚分配,VPTR 还未初始化 —— 此时虚函数的调用逻辑(通过 VPTR 找 VTABLE)根本无法工作。

5.构造函数不能定义为虚函数,而析构函数可以定义为虚函数。

class Base_demo { public: virtual void Demo() { cout << "这是基类Base" << endl; } virtual ~Base_demo() { cout << "析构Base" << endl; } }; class Derived_demo :public Base_demo { public: void Demo() { cout << "这是派生类Derived" << endl; } ~Derived_demo() { cout << "析构Derived" << endl; } }; int main() { Base_demo * b2, * d2; b2 = new Base_demo(); d2 = new Derived_demo(); delete b2; delete d2; return 0; }

虚函数表和虚指针

在编译时,为每个有虚函数的类建立一张虚函数表VTABLE,表中存放的是每一个虚函数的指针;同时用一个虚指针VPTR指向这张表的入口。

访问某个虚函数时,不是直接找到那个函数的地址,而是通过VPTR间接查到它的地址。

int main(){ Base_demo b1; Base_demo* b2 = &b1; b2->Demo(); Derived_demo d1; Base_demo* b2 = &d1; b2->Demo(); }

对于基类Base_demo的对象b1:
b1的内存空间:包含自己的data members(这里我没定义成员变量,所以只有VPTR)+VPTR(虚指针);
b1的 VPTR 指向 Base_demo的 VTABLE(虚函数表),这个表中存的是Base_demo::Demo()的函数地址。
对于子类Derived_demo的对象d1
d1的内存空间:包含Base_demo的data members(继承的) +自己的data members+VPTR;
d1的 VPTR 指向 Derived_demo的 VTABLE,这个表中存的是Derived_demo::Demo()的函数地址。

纯虚函数与抽象类

定义纯虚函数的语法形式: virtual type functionName(parameters)=0;

纯虚函数:基类中的公共接口只需要有说明而不需要有实现,即纯虚函数。纯虚函数刻画了派生类应该遵循的协议,这些协议的具体实现由派生类来决定。

抽象类:拥有纯虚函数的类被称为抽象类。抽象类不能被实例化,只能作为基类被使用。抽象类的派生类需要实现纯虚函数,否则该派生类也是一个抽象类。

接口类:当抽象类的所有函数成员都是纯虚函数时,这个类被称为接口类。

class Shape{ virtual float Perimeter()=0; virtual float Area()=0; };

Shape类中的Perimeter与Area就是纯虚函数,而Shape则是抽象类。又可以看到类中成员全是虚函数,所以Shape也是一个接口类

没什么用的小知识:

特殊规则:注意一点,纯虚函数的重写不受访问限制,即使这里没用写public默认的private子类也可以重写。但通过父类指针调用私有虚函数是不合法的。所以一般我们还是要遵守访问限定域。

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

多继承与虚基类

多继承派生类的语法格式&#xff1a;class 派生类名 : <继承方式1> 基类名1,<继承方式2> 基类名2,…… { ……//派生类新添加的成员};多继承派生类对象的构造和析构:派生类名(参数表):基类名1(参数表1),基类名2(参数表2),对象成员1(参数表3),对象成员2(参数…

作者头像 李华
网站建设 2026/5/30 4:16:56

电子产品EMC整改:智能化设计工具重塑电磁兼容性优化|南柯电子

在万物互联的智能时代&#xff0c;电子产品的电磁兼容性&#xff08;EMC&#xff09;已成为决定产品市场准入与可靠性的核心指标。从消费电子到工业设备&#xff0c;从新能源汽车到医疗仪器&#xff0c;EMC问题不仅关乎设备自身的稳定运行&#xff0c;更直接影响用户安全与行业…

作者头像 李华
网站建设 2026/5/29 20:12:35

APP自动化第一步:Appium环境搭建

一、安装Appium Python client包 1.直接cmd窗口输入pip install Appium-Python-Client 2.要确保安装匹配版本的selenium和appium 使用命令pip install selenium -U 首先进入网盘下载这三个软件的压缩包 二、安装Appium Server 1.双击打开压缩包Appium 2.双击进行安装。 3.点…

作者头像 李华
网站建设 2026/5/29 23:00:21

【专家亲授】量子机器学习环境搭建:VSCode核心参数调优9大秘诀

第一章&#xff1a;量子机器学习与VSCode集成概览量子机器学习&#xff08;Quantum Machine Learning, QML&#xff09;是量子计算与经典机器学习深度融合的前沿领域&#xff0c;利用量子态叠加、纠缠等特性加速模型训练或提升预测能力。随着开发工具生态的成熟&#xff0c;将Q…

作者头像 李华
网站建设 2026/5/29 5:07:55

iFlow-CLI独家实测 开源模型中最会写代码的 MiMo-V2-Flash效果如何?

前言 小米今日发布了开源基座大模型 MiMo-V2-Flash。这款模型采用了Mixture-of-Experts (MoE) 架构&#xff0c;总参数规模达到 3090 亿&#xff0c;激活参数 150 亿&#xff0c;通过混合注意力机制的创新设计&#xff0c;在保持高性能的同时实现了推理效率的极致优化。 在代…

作者头像 李华
网站建设 2026/5/29 13:42:43

从入门到精通:Docker Buildx构建上下文控制的8个最佳实践

第一章&#xff1a;Docker Buildx构建上下文的核心概念Docker Buildx 是 Docker 官方提供的一个 CLI 插件&#xff0c;扩展了原生 docker build 命令的能力&#xff0c;支持多平台构建、并行执行和更高效的构建流程。其核心优势之一在于对“构建上下文&#xff08;Build Contex…

作者头像 李华