news 2026/4/16 12:40:08

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

作者头像

张小明

前端开发工程师

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/4/16 12:03:57

Nacos服务注册与配置中心实战指南

本文详解Nacos的部署配置与实战应用&#xff0c;实现微服务的服务发现和统一配置管理。 前言 微服务架构的两大核心问题&#xff1a; 服务发现&#xff1a;服务实例动态变化&#xff0c;如何找到对方&#xff1f;配置管理&#xff1a;配置分散各处&#xff0c;如何统一管理&a…

作者头像 李华
网站建设 2026/4/16 12:04:52

写简历时总觉得内容太多?这 10 个在线简历网站,能帮你理清结构

很多人在写简历时都会陷入一个矛盾&#xff1a; 每段经历都不想删&#xff0c;但又怕简历太长、重点不清。 尤其是毕业生和实习生&#xff0c;往往不是没内容&#xff0c;而是不知道该怎么排、怎么取舍。 参考一些成熟的在线简历工具&#xff0c;其实能学到不少排版结构和内容…

作者头像 李华
网站建设 2026/4/16 3:54:41

如何快速上手BDInfo:蓝光光盘信息分析的终极指南

如何快速上手BDInfo&#xff1a;蓝光光盘信息分析的终极指南 【免费下载链接】BDInfo BDInfo from http://www.cinemasquid.com/blu-ray/tools/bdinfo 项目地址: https://gitcode.com/gh_mirrors/bd/BDInfo BDInfo是一款功能强大的蓝光光盘信息分析工具&#xff0c;能够…

作者头像 李华
网站建设 2026/4/16 12:02:08

​潮玩盲盒小程序开发、商业价值提升!​

潮玩盲盒小程序开发、商业价值提升&#xff01;现在&#xff0c;年轻消费者倾向于通过手机完成购物、社交和娱乐活动&#xff0c;盲盒小程序结合了传统盲盒销售方式&#xff0c;以电商的购物方式进一步激发消费者的消费欲望&#xff0c;推动线上盲盒市场的发展&#xff0c;是一…

作者头像 李华
网站建设 2026/4/16 7:20:59

你真的会写量子代码吗?5个高阶VSCode示例让你少走3年弯路

第一章&#xff1a;量子算法的 VSCode 示例代码 在现代量子计算开发中&#xff0c;Visual Studio Code&#xff08;VSCode&#xff09;已成为主流集成开发环境之一。借助 Q#、Qiskit 等量子编程框架的扩展支持&#xff0c;开发者可以在本地快速构建、模拟和调试量子算法。 配置…

作者头像 李华