news 2026/6/23 20:18:53

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

作者头像

张小明

前端开发工程师

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/6/23 19:28:27

better-sqlite3深度解析:Node.js数据库操作的性能革命

better-sqlite3深度解析&#xff1a;Node.js数据库操作的性能革命 【免费下载链接】better-sqlite3 The fastest and simplest library for SQLite3 in Node.js. 项目地址: https://gitcode.com/gh_mirrors/be/better-sqlite3 在Node.js生态系统中&#xff0c;数据库操作…

作者头像 李华
网站建设 2026/6/23 0:19:15

终极AI平台wgai:零门槛构建国产化智能识别系统

终极AI平台wgai&#xff1a;零门槛构建国产化智能识别系统 【免费下载链接】wgai 开箱即用的JAVAAI在线训练识别平台&OCR平台AI合集包含旦不仅限于(车牌识别、安全帽识别、抽烟识别、常用类物识别等) 图片和视频识别&#xff0c;可自主训练任意场景融合了AI图像识别opencv、…

作者头像 李华
网站建设 2026/6/22 16:23:51

基于VUE的企业协同管理系统 [VUE]-计算机毕业设计源码+LW文档

摘要&#xff1a;随着企业规模的扩大和业务的复杂化&#xff0c;企业内部的协同工作效率成为影响企业竞争力的关键因素。本文介绍了一种基于VUE框架开发的企业协同管理系统&#xff0c;详细阐述了系统的需求分析、技术选型、架构设计、功能模块实现等内容。该系统涵盖了系统用户…

作者头像 李华
网站建设 2026/6/22 11:52:23

如何快速使用bandcamp-dl:命令行音乐下载工具的完整教程

如何快速使用bandcamp-dl&#xff1a;命令行音乐下载工具的完整教程 【免费下载链接】bandcamp-dl Simple python script to download Bandcamp albums 项目地址: https://gitcode.com/gh_mirrors/ba/bandcamp-dl Bandcamp-dl是一款功能强大的开源工具&#xff0c;专门用…

作者头像 李华
网站建设 2026/6/20 20:24:16

【Excel VBA 编程】第61讲:两种方法驾驭文本处理猛兽

VBA正则表达式中引入贪婪匹配与惰性匹配两种模式&#xff0c;本质上是为编程者提供控制匹配“粒度” 的关键工具。因此&#xff0c;理解并正确运用这两种模式&#xff0c;能够有效解决文本处理中常见的边界模糊问题&#xff0c;快速实现精准数据提取和文本分析贪婪匹配上一期我…

作者头像 李华