news 2026/5/27 6:40:38

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

作者头像

张小明

前端开发工程师

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/26 1:16:02

小米 MiMo-V2-Flash 快速接入 iFlow-CLI 保姆级教程

教程 1、登录小米开放者平台&#xff0c;并进入控制台&#xff1a;Xiaomi MiMo 开放平台 2、点击左侧“API-Keys”栏&#xff0c;再创建API-Key 3、启动iFlow-CLI&#xff0c;输入指令/auth&#xff0c;选择第三种登录方式&#xff1a;“OpenAI 兼容 API” 4、在base URL输入框…

作者头像 李华
网站建设 2026/5/25 6:53:34

MCP量子编程培训材料深度解析(量子计算时代的职业跳板)

第一章&#xff1a;MCP量子编程认证概述MCP量子编程认证&#xff08;Microsoft Certified Professional in Quantum Programming&#xff09;是微软面向量子计算开发者推出的权威技术认证&#xff0c;旨在验证开发者在Q#语言、量子算法设计与Azure Quantum平台应用方面的专业能…

作者头像 李华
网站建设 2026/5/26 6:18:37

CST通过Save As Protected功能对工程进行加密保护

对外发资料有加密要求的用户&#xff0c;使用Save As Protected功能可以实现既呈现仿真结果&#xff0c;又对结构、材料、端口设置等内容进行加密保护。使用该功能时&#xff0c;需要先要保存一下工程。在保存状态下选择File > Project > Save As Protected,便可打开加密…

作者头像 李华
网站建设 2026/5/26 5:17:32

macOS窗口管理工具深度解析:从新手到专家的进阶指南

macOS窗口管理工具深度解析&#xff1a;从新手到专家的进阶指南 【免费下载链接】open-source-mac-os-apps serhii-londar/open-source-mac-os-apps: 是一个收集了众多开源 macOS 应用程序的仓库&#xff0c;这些应用程序涉及到各种领域&#xff0c;例如编程、生产力工具、游戏…

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

【AI工程化核心突破】:如何用Docker快速部署可扩展的智能Agent集群

第一章&#xff1a;智能 Agent 集群部署的挑战与演进随着分布式系统和人工智能技术的深度融合&#xff0c;智能 Agent 集群在边缘计算、自动驾驶协同、工业自动化等场景中扮演着关键角色。然而&#xff0c;其大规模部署面临诸多挑战&#xff0c;包括异构环境适配、动态负载均衡…

作者头像 李华