C++ 进阶:深入理解虚函数、继承与多态

前言

在 C++ 的面向对象编程中,继承和多态是两个核心概念。今天我们将深入探讨 C++ 中与多态密切相关的几个重要特性:虚函数、virtual 关键字、override 关键字、多重继承以及虚继承。这些内容是理解 C++ 多态机制和复杂类层次结构的关键。

虚函数与 virtual 关键字

虚函数的基本概念

虚函数是实现运行时多态的基础。通过虚函数,我们可以在基类中定义一个接口,而在派生类中重写这个接口,从而在程序运行时根据对象的实际类型调用相应的函数。

virtual 关键字的使用

在基类中,使用 virtual 关键字声明一个函数为虚函数。例如:

class Base {
public:virtual void show() {std::cout << "Base class show function" << std::endl;}
};class Derived : public Base {
public:void show() override {  // 重写虚函数std::cout << "Derived class show function" << std::endl;}
};

在上面的代码中,Base 类的 show 函数被声明为虚函数,Derived 类重写了这个虚函数。当我们通过基类指针或引用调用 show 函数时,会根据对象的实际类型调用相应的函数:

int main() {Base* basePtr = new Derived();basePtr->show();  // 输出: Derived class show functiondelete basePtr;return 0;
}

虚函数的工作原理

虚函数通过虚函数表(vtable)实现。每个包含虚函数的类都有一个虚函数表,表中存储了该类所有虚函数的地址。当创建对象时,对象内部会包含一个指向虚函数表的指针(vptr)。在调用虚函数时,程序会根据对象的 vptr 找到对应的虚函数表,然后根据函数在表中的位置调用相应的函数。

override 关键字

override 的作用

override 关键字是 C++11 引入的,用于明确表示一个函数是重写基类的虚函数。它的主要作用是:

  1. 提高代码可读性:让其他开发者清楚地知道这个函数是重写基类的虚函数。
  2. 防止拼写错误:如果基类中没有对应的虚函数,编译器会报错,避免因拼写错误导致的隐藏而非重写的问题。

使用示例

class Base {
public:virtual void display() {std::cout << "Base class display function" << std::endl;}
};class Derived : public Base {
public:void display() override {  // 正确重写std::cout << "Derived class display function" << std::endl;}// void dispaly() override {  // 拼写错误,编译器会报错//     std::cout << "Wrong function" << std::endl;// }
};

多重继承

多重继承的基本概念

多重继承是指一个派生类可以同时继承多个基类。这使得派生类可以拥有多个基类的属性和方法。例如:

class Base1 {
public:void show1() {std::cout << "Base1 class show1 function" << std::endl;}
};class Base2 {
public:void show2() {std::cout << "Base2 class show2 function" << std::endl;}
};class Derived : public Base1, public Base2 {
public:void showAll() {show1();show2();}
};

在上面的代码中,Derived 类同时继承了 Base1Base2 类,因此可以调用 Base1Base2 中的成员函数。

多重继承的问题

多重继承虽然提供了更大的灵活性,但也带来了一些问题:

  1. 菱形继承问题:当多个基类有共同的基类时,派生类中会出现多个共同基类的子对象,导致数据冗余和二义性。
  2. 命名冲突:如果多个基类中有同名的成员函数或成员变量,派生类中直接使用会导致二义性。

菱形继承示例

class Grandparent {
public:int value;
};class Parent1 : public Grandparent {
};class Parent2 : public Grandparent {
};class Child : public Parent1, public Parent2 {
public:void printValue() {// std::cout << value << std::endl;  // 编译错误,二义性std::cout << Parent1::value << std::endl;  // 明确指定std::cout << Parent2::value << std::endl;}
};

在上面的代码中,Child 类同时继承了 Parent1Parent2 类,而 Parent1Parent2 类又都继承了 Grandparent 类,导致 Child 类中有两个 value 成员,直接使用 value 会导致二义性。

虚继承

虚继承的引入

为了解决多重继承中的菱形继承问题,C++ 引入了虚继承。虚继承使得派生类只继承共同基类的一份子对象,避免了数据冗余和二义性。

虚继承的使用

在继承时,使用 virtual 关键字指定虚继承。例如:

class Grandparent {
public:int value;
};class Parent1 : virtual public Grandparent {  // 虚继承
};class Parent2 : virtual public Grandparent {  // 虚继承
};class Child : public Parent1, public Parent2 {
public:void printValue() {std::cout << value << std::endl;  // 现在可以正常使用}
};

在上面的代码中,Parent1Parent2 类都虚继承了 Grandparent 类,因此 Child 类中只有一个 Grandparent 类的子对象,value 成员可以直接使用。

虚继承的工作原理

虚继承通过虚基类表(vbtable)实现。虚基类表存储了虚基类子对象在派生类对象中的偏移量等信息。在创建派生类对象时,编译器会根据虚基类表来正确初始化虚基类子对象,确保每个虚基类子对象在派生类对象中只存在一份。

总结

  • 虚函数和 virtual 关键字:实现运行时多态,通过虚函数表实现函数调用。
  • override 关键字:明确表示重写基类虚函数,提高代码可读性和防止拼写错误。
  • 多重继承:允许派生类同时继承多个基类,但可能带来菱形继承和命名冲突问题。
  • 虚继承:解决多重继承中的菱形继承问题,通过虚基类表确保共同基类子对象只存在一份。

理解这些概念对于编写高效、可维护的 C++ 代码至关重要。在实际开发中,合理运用这些特性可以构建出更加灵活和强大的类层次结构。希望这篇博客能帮助你更好地掌握 C++ 中的这些重要概念。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/85115.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/85115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为AR眼镜等多种智能可穿戴设备添加穿戴状态检测功能

作者&#xff1a;Azoteq中国 随着AR/VR眼镜、头戴式耳机和入耳式耳塞、智能手表和健身手环等可穿戴电子产品受到越来越多消费者的欢迎&#xff0c;如何设计外形更加时尚迷人、功能更加先进宜人的穿戴产品成为了创新和创意的焦点。作为全球领先的多传感器解决方案提供商&#xf…

腾讯云国际站缩容:策略、考量与实践

腾讯云国际站作为连接全球业务的重要云计算枢纽&#xff0c;其资源的灵活调配至关重要。而腾讯云国际站缩容&#xff0c;便是企业在特定发展阶段或业务场景下需要深入探究的关键议题。 一、腾讯云国际站缩容的背景与动因 随着企业业务的动态发展&#xff0c;市场需求并非一成…

英语写作核心词汇

以下是一些非常常见和实用的单词和短语分类整理&#xff1a;​ 1. 核心高频动词 (用于表达观点、影响、变化等) ​Affect (v.): 影响​Cause (v.): 引起&#xff0c;导致​Influence (v./n.): 影响​Benefit (v./n.): 有益于&#xff1b;好处​Harm (v./n.): 损害&#xff1b…

Python函数参数传递机制全解析

Python常见问题解答 1. 函数参数传递是值传递还是引用传递&#xff1f; Python中的参数传递是"对象引用传递"&#xff08;或称为"共享对象传递"&#xff09;。具体来说&#xff1a; 对于不可变对象&#xff08;如数字、字符串、元组&#xff09;&#x…

MATLAB提供的预训练神经网络

CNN 预训练的神经网络 Deep Learning Toolbox™ provides various pretrained networks that have different sizes, speeds, and accuracies.

【PDF】Qt生成PDF文件,占用存储小

在 Qt 项目中&#xff0c;如果你希望使用第三方开源库来生成心电图的 PDF 报告&#xff0c;并且要求占用磁盘空间最小&#xff0c;以下是一些推荐的选择&#xff1a; 推荐的开源库 PoDoFo 简介&#xff1a;PoDoFo 是一个用于创建和操作 PDF 文件的 C 开源库。它非常轻量级&…

系统架构设计师 1

第一章 绪论 系统架构设计师(System Architecture Designer)是项目开发活动中的关键角色之一。系统架构是系统的一种整体的高层次的结构表示&#xff0c;是系统的骨架和根基&#xff0c;其决定了系统的健壮性和生命周期的长短。 1.1 系统架构概述 1946年第一台计算机&#x…

2023年面试记录(base杭州)

阿里外包&#xff08;通过&#xff09; 一面&#xff1a; 1、react 常用hook 2、css的重绘和重排 后面如果进入还有两轮 二面&#xff1a; 1、解决不同版本的兼容问题能句几个例子吗 2、FCP和 CLS 这两个指标是什么意思能讲下吗 3、具体优化的动作是什么呢 4、放到cdn上为什么…

React 国际化方案最佳实践调研

文章目录 前言主流国际化库对比分析翻译资源管理策略语言切换方式与自动识别Next.js 中的国际化支持Page Router 模式&#xff08;pages 目录&#xff09;App Router 模式&#xff08;app 目录&#xff09; 多语言 SEO 与预渲染注意事项企业级多语言开发与协作流程建议 前言 整…

基于Python实现自然语言处理(主题层次的情感分类)

主题层次的情感分类 1 任务及数据集介绍 该项目作业的具体任务是来自于 BDCI2018-汽车行业用户观点主题及情感识别的题目。数据是网络中公开的用户对汽车相关内容的评价文本。此任务是对每条文本内容&#xff08;即用户评论&#xff09;进行分析&#xff0c;确定该条评论中讨…

SpringBoot 线程池 配置使用详解

一、核心特性 Springboot 集成 支持 Async 注解&#xff0c;简化异步方法调用。 参数可配置化 核心线程数、最大线程数、队列容量、拒绝策略等均可通过配置调整。 生命周期管理 实现 Lifecycle 接口&#xff0c;支持线程池的启动和关闭&#xff08;如应用关闭时优雅终止任务…

Elasticsearch/OpenSearch MCP Quickstart

项目概述 elasticsearch-mcp-server 是一个基于 Model Context Protocol (MCP) 的服务器实现&#xff0c;提供了与 Elasticsearch 和 OpenSearch 交互的能力。该服务器允许用户搜索文档、分析索引以及管理集群&#xff0c;通过一系列工具函数实现这些功能。 项目结构 项目主…

《Elasticsearch 分布式搜索在聊天记录检索中的深度优化》

Elasticsearch 分布式搜索在聊天记录检索中的深度优化 引言 在现代聊天应用中&#xff0c;聊天记录检索面临着数据量大、查询复杂、实时性要求高的多重挑战。以某社交平台为例&#xff0c;其聊天记录每天新增数千万条&#xff0c;总数据量达百亿级&#xff0c;用户需要在海量…

CSS实现元素撑满剩余空间的5种方法

CSS实现元素撑满剩余空间的5种方法 &#x1f3a8; 在日常开发中&#xff0c;我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求&#xff0c;比如侧边栏主内容区、头部内容区底部等布局。本文将介绍5种不同的方法来实现这个需求&#xff0c;并分析各种方法的优…

[AI]从零开始的YOLO数据集增强教程

一、前言 不知道大家在训练YOLO时有没有遇到过这样的情况&#xff0c;明明数据集已经准备了很多了&#xff0c;但是YOLO还是不认识某个物品&#xff0c;或者置信度低。那么有没有办法让我们不制作新数据集的情况下让代码帮我们生成新的数据集来训练模型呢&#xff1f;当然有&am…

软件工程的相关名词解释

目录 1. 软件生命周期2.开源软件3.软件工程4.模块化原则5.信息隐藏原则6.双向追踪7.原型8.软件需求9.需求工程10.边界类11.软件实现&#xff08;的任务&#xff09;12.软件缺陷13.回归测试14.软件β版15.软件部署16.纠正性维护17.改善性维护18.适应性维护19.软件逻辑老化 1. 软…

2025.06.17【BUG】|多样品VCF文件合并技巧及注意事项(以bcftools为例)

文章目录 [toc]一、合并VCF的常用命令1.1 合并多个bgzip压缩的VCF文件1.2 使用文件列表合并 二、合并前的准备与注意事项2.1 文件格式要求2.2 样本名唯一性2.3 检查文件模式匹配 三、常见报错与解决方法3.1 报错&#xff1a;Error: Duplicate sample names (sample1), use --fo…

包含30个APP客户端UI界面的psd适用于旅游酒店项目

包含30个APP客户端UI界面的psd适用于旅游酒店项目 此资源包含30个完全可编辑的psd界面组成。内容包括欢迎页、登录、注册、首页、搜索、侧边菜单、用户中心、个人介绍、用户空间、产品详细信息、酒店预定、天气情况等各种常用界面&#xff0c;您可以将其用于旅游酒店类的APP应用…

ArrayList源码分析

目录 ArrayList简介 ArrayList和vector的区别&#xff08;了解即可&#xff09; ArrayList添加null值 ArrayList和LinkedList区别 ArrayList核心源码解读 ArrayList扩容机制分析 一步一分析ArrayList扩容机制 hugeCapacity()方法 System.arraycopy() Arrays.copyOf()方法 …

NX二次开发C#---通过Face找Edges,再通过Edges找Curve

文章介绍了一个名为AskFaceEdge的静态方法&#xff0c;用于处理3D建模中的边缘曲线生成。该方法通过NX Open API调用&#xff0c;主要功能是获取指定面的边缘并生成相应的曲线。方法接收两个参数&#xff1a;faceTag&#xff08;面标签&#xff09;和curveLoop&#xff08;曲线…