每日一问:C++ 如何实现继承、封装和多态
每日一问:C++ 如何实现继承、封装和多态
C++ 是一门面向对象编程语言,通过继承、封装和多态这三个核心特性实现了对复杂系统的高效管理和扩展。继承让代码重用性得以提升,封装保护数据的完整性,而多态通过不同的接口实现了灵活性。本文将详细讲解 C++ 如何实现继承、封装和多态,探讨各自的实现机制及实际应用。
文章目录
- 每日一问:C++ 如何实现继承、封装和多态
- 摘要
- 一、继承:实现代码复用
- 1.1 继承的基本概念
- 1.2 继承的实现方式
- 1.3 多重继承与虚基类
- 二、封装:保护数据的完整性
- 2.1 封装的基本概念
- 2.2 封装的实现方式
- 2.3 组合与聚合
- 三、多态:提升系统的灵活性
- 3.1 多态的基本概念
- 3.2 多态的实现方式
- 3.3 动态绑定与静态绑定
- 3.4 多态的应用场景
- 四、总结
摘要
本文探讨了 C++ 中实现继承、封装和多态的方式,包括类的定义与成员函数、访问权限控制、虚函数与纯虚函数、函数重载与重写等。通过代码示例,详细讲解了这些概念在 C++ 中的实际应用,帮助读者理解面向对象编程的精髓。
一、继承:实现代码复用
1.1 继承的基本概念
继承是 C++ 提供的代码复用机制,通过继承,派生类(Derived Class)可以直接继承基类(Base Class)的属性和方法,从而避免重复代码。继承的关键在于扩展现有类的功能,同时保持逻辑的一致性。
1.2 继承的实现方式
- 基类与派生类:通过定义一个基类,然后让其他类继承该基类,从而复用基类中的代码。
- 访问权限控制:继承中可以通过
public、protected和private控制派生类对基类成员的访问权限。
示例代码:
#include <iostream>
using namespace std;// 定义一个基类 Animal
class Animal {
public:void eat() { // 基类的成员函数cout << "Eating..." << endl;}
};// 定义一个派生类 Dog,继承自 Animal
class Dog : public Animal {
public:void bark() { // 派生类的成员函数cout << "Barking..." << endl;}
};int main() {Dog dog; // 创建派生类对象dog.eat(); // 调用继承自基类的函数dog.bark(); // 调用派生类自己的函数return 0;
}
解释:在这个示例中,Dog 类继承了 Animal 类,得以直接使用基类的 eat() 方法,同时扩展了自己的 bark() 方法。
1.3 多重继承与虚基类
C++ 支持多重继承,即一个类可以同时继承多个基类。但这也可能带来“菱形继承”问题,为此引入了虚基类(Virtual Base Class)解决重复继承的问题。
示例代码:
#include <iostream>
using namespace std;// 定义虚基类 A
class A {
public:void show() {cout << "Class A" << endl;}
};// 定义 B 和 C 类,虚继承自 A
class B : virtual public A {};
class C : virtual public A {};// 定义 D 类,继承自 B 和 C
class D : public B, public C {};int main() {D d; // 创建 D 类对象d.show(); // 调用 show 函数,避免菱形继承问题return 0;
}
解释:虚基类通过消除重复继承的问题,确保了 A 类只会被继承一次,从而避免数据冗余。
二、封装:保护数据的完整性
2.1 封装的基本概念
封装是将数据和操作封装在一个类中,通过访问控制保护数据不被非法访问。C++ 通过访问控制符 public、protected 和 private 实现封装,确保对象的内部状态只能通过合法的方式改变。
2.2 封装的实现方式
- 访问控制:
public用于对外开放的成员,protected对继承的派生类开放,private对类外部完全隐藏。 - 构造函数与析构函数:通过构造函数和析构函数控制对象的初始化和销毁,确保对象在合适的状态下创建和销毁。
示例代码:
#include <iostream>
using namespace std;// 定义类 Box,演示封装
class Box {
private:double length; // 私有成员变量double width; // 私有成员变量public:// 构造函数Box(double l, double w) : length(l), width(w) {}// 公有成员函数,获取面积double getArea() {return length * width;}
};int main() {Box box(5.0, 3.0); // 创建 Box 对象cout << "Area: " << box.getArea() << endl; // 访问公有成员函数return 0;
}
解释:Box 类通过封装,将 length 和 width 设置为私有,仅通过公有函数 getArea() 对外暴露,这种封装方式保护了数据的完整性。
2.3 组合与聚合
组合和聚合是将类组合起来形成复杂对象的方式。组合是强关联,表示成员对象的生命周期与类对象绑定;聚合是弱关联,成员对象的生命周期独立于类对象。
示例代码:
#include <iostream>
#include <string>
using namespace std;class Engine {
public:void start() {cout << "Engine started." << endl;}
};// Car 类组合了 Engine 类
class Car {
private:Engine engine; // 组合关系,Car 拥有 Enginepublic:void start() {engine.start(); // 使用 Engine 对象的成员函数cout << "Car started." << endl;}
};int main() {Car car; // 创建 Car 对象car.start(); // 调用 Car 对象的 start 函数return 0;
}
解释:在这个示例中,Car 类组合了 Engine 类,通过 engine 对象调用 start() 方法,展示了组合关系。
三、多态:提升系统的灵活性
3.1 多态的基本概念
多态是指同一接口可以有不同实现的能力,它是面向对象编程的核心。C++ 通过函数重载、运算符重载、虚函数和纯虚函数实现多态。多态可以分为静态多态和动态多态。
3.2 多态的实现方式
- 重载:在同一作用域中定义多个同名但参数不同的函数,属于静态多态(编译时多态)。
- 重写:派生类重新定义基类中的虚函数,实现动态多态(运行时多态)。
- 虚函数与纯虚函数:通过虚函数实现动态绑定,通过纯虚函数定义接口,强制派生类实现接口方法。
示例代码:
#include <iostream>
using namespace std;// 基类 Shape,定义纯虚函数
class Shape {
public:virtual void draw() = 0; // 纯虚函数,定义接口
};// 派生类 Circle,重写基类的 draw 函数
class Circle : public Shape {
public:void draw() override { // 重写 draw 函数cout << "Drawing a circle." << endl;}
};// 派生类 Rectangle,重写基类的 draw 函数
class Rectangle : public Shape {
public:void draw() override { // 重写 draw 函数cout << "Drawing a rectangle." << endl;}
};int main() {Shape* shape1 = new Circle(); // 创建 Circle 对象Shape* shape2 = new Rectangle(); // 创建 Rectangle 对象shape1->draw(); // 调用 Circle 的 draw 函数shape2->draw(); // 调用 Rectangle 的 draw 函数delete shape1; // 释放对象内存delete shape2; // 释放对象内存return 0;
}
解释:在这个示例中,Shape 类定义了一个纯虚函数 draw(),Circle 和 Rectangle 分别重写该函数,实现了动态多态。
3.3 动态绑定与静态绑定
静态绑定是在编译时确定调用的函数(如重载),而动态绑定是在运行时根据对象类型确定调用的函数(如重写)。
3.4 多态的应用场景
多态在设计模式中的应用广泛,如工厂模式和策略模式。工厂模式通过返回基类指针,实现对象的创建与替换;
策略模式允许在运行时选择具体实现。
示例代码:
#include <iostream>
#include <memory>
using namespace std;// 定义抽象基类 PaymentStrategy
class PaymentStrategy {
public:virtual void pay() = 0; // 纯虚函数,定义支付方法接口
};// 定义具体策略类 CreditCardPayment
class CreditCardPayment : public PaymentStrategy {
public:void pay() override {cout << "Paying with Credit Card." << endl;}
};// 定义具体策略类 PayPalPayment
class PayPalPayment : public PaymentStrategy {
public:void pay() override {cout << "Paying with PayPal." << endl;}
};// 购物车类,使用策略模式
class ShoppingCart {
private:PaymentStrategy* strategy; // 策略模式中的支付策略public:ShoppingCart(PaymentStrategy* s) : strategy(s) {}void checkout() {strategy->pay(); // 执行具体支付策略}
};int main() {PaymentStrategy* pay1 = new CreditCardPayment();PaymentStrategy* pay2 = new PayPalPayment();ShoppingCart cart1(pay1); // 使用信用卡支付策略ShoppingCart cart2(pay2); // 使用 PayPal 支付策略cart1.checkout(); // 调用信用卡支付cart2.checkout(); // 调用 PayPal 支付delete pay1;delete pay2;return 0;
}
解释:在上述代码中,通过策略模式实现了动态选择不同支付方式的功能,这展示了多态在实际应用中的灵活性和扩展性。
四、总结
继承、封装和多态是 C++ 面向对象编程的核心。通过继承实现代码复用,通过封装保护数据完整性,通过多态提升系统灵活性。理解这些机制不仅能提升编程能力,还能设计出高效、灵活且可维护的系统。
| 特性 | 实现方式 | 关键机制 |
|---|---|---|
| 继承 | 基类与派生类、多重继承与虚基类 | 代码复用、继承关系、消除重复继承问题 |
| 封装 | 访问控制、构造与析构函数、组合与聚合 | 保护数据完整性、控制对象生命周期 |
| 多态 | 函数重载、重写、虚函数与纯虚函数 | 静态绑定、动态绑定、灵活接口实现 |
通过这些特性,C++ 程序能够更好地管理复杂性,提高代码的复用性和可维护性。在实际编程中,根据需求选择合适的机制,能有效提升软件开发的质量和效率。
相关文章:
每日一问:C++ 如何实现继承、封装和多态
每日一问:C 如何实现继承、封装和多态 C 是一门面向对象编程语言,通过继承、封装和多态这三个核心特性实现了对复杂系统的高效管理和扩展。继承让代码重用性得以提升,封装保护数据的完整性,而多态通过不同的接口实现了灵活性。本文…...
STM32常用数据采集滤波算法
例如,STM32进行滤波处理时,主要目的是处理数据采集过程中可能产生的噪声和尖刺信号。这些噪声可能来自电源干扰、传感器自身的不稳定性或其他外部因素。 1.一阶互补滤波 方法:取a0~1,本次滤波结果(1-a)本次采样值a上…...
二分系列(二分查找)9/12
一、分情况讨论 1.左闭右闭:[left,right] 因为是左闭右闭,所以left和right都能直接取到。 #这里将>放到一起,当nums[mid]>target的时候, 要更新右边界,rightmid-1,这样就把一些相同的情况也切出去了 可以理解为找的第一个…...
如何通过可视化大屏,助力智慧城市的“城市微脑”建设?
在智慧城市的宏伟蓝图中,常常面临着一个关键挑战:如何确保这些理念和技术能够真正地惠及城市的每一个角落,每一个产业,以及每一位市民。问题的核心在于城市的具体应用场景,无论是横向的社区、园区、镇街、学校、酒店、…...
何时空仓库
某仓库现存货物 s 箱,每天上午出货 m 箱、下午进货 n 箱,若s≥m>n≥0,则第 k 天将会出现空仓的情况。请你帮仓库管理员编写程序,输入s、m 和 n,计算并输出 k。 输入格式 s,m,n (s≥m>n≥0) 输出格式 k 输入样例…...
美创获评CNVD年度原创漏洞发现贡献单位!
9月10日,第21届中国网络安全年会暨网络安全协同治理分论坛在广州成功举办。会上,美创科技首次获评“CNVD年度原创漏洞发现贡献单位”。 美创科技依托第59号安全实验室,专注数据安全技术和攻防研究。凭借深厚的技术积累与优势,被遴…...
Spring 循环依赖原理及解决方案
一、什么是循环依赖 循环依赖指的是一个实例或多个实例存在相互依赖的关系(类之间循环嵌套引用)。 举例: Component public class AService {// A中注入了BAutowiredprivate BService bService; }Component public class BService {// B中也…...
【数据结构与算法 | 灵神题单 | 插入链表篇】力扣2807, LCR 029, 147
1. 力扣2807:在链表中插入最大公约数 1.1 题目: 你一个链表的头 head ,每个结点包含一个整数值。 在相邻结点之间,请你插入一个新的结点,结点值为这两个相邻结点值的 最大公约数 。 请你返回插入之后的链表。 两个…...
瑞芯微rv1126 Linux 系统,修改系统时区,包有效方法
在 Linux 系统中,修改时区的步骤通常包括创建符号链接到正确的时区文件,并确保相关的配置文件已正确更新。然而,某些系统可能有额外的步骤或需要修改其他配置文件来使更改生效。以下是一些步骤。 1. 创建符号链接 ln -sf /usr/share/zoneinfo/Asia/Hong_Kong /etc/localti…...
系统架构设计师:数据库设计
简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师:数据库设计前言数据库基础概念数据模型三要素数据库的三级模型和两级…...
代码随想录刷题day31丨56. 合并区间,738.单调递增的数字,总结
代码随想录刷题day31丨56. 合并区间,738.单调递增的数字,总结 1.题目 1.1合并区间 题目链接:56. 合并区间 - 力扣(LeetCode) 视频讲解:贪心算法,合并区间有细节!LeetCode&#x…...
深圳建站公司-如何做网站
深圳建站公司:如何制作一个成功的网站 在信息化快速发展的今天,企业和个人越来越重视网络形象,网站成为了展示品牌、推广产品和服务的重要平台。深圳作为科技创新和经济发展的前沿城市,涌现出许多专业的建站公司,能够为…...
Google Earth Engine(GEE)——随时间推移的降雨趋势案例分析(大规模气候监测)
简介 探索 Google Earth Engine环境类型中不同的数据。到目前为止,我们主要使用光学卫星数据,并探索了植被随时间和空间的趋势。然而,仅仅跟踪植被特性的变化并不足以了解是什么驱动了它们——我们需要能够将这些动态与其他环境数据联系起来。 在交互式 GEE 控制台中为您感…...
从新手到高手:用这9个策略让ChatGPT成为你的私人顾问!
ChatGPT已经出来快一年多了,但是我发现周围的小伙伴还是处在调戏ChatGPT的阶段,并没有在日常工作和生活中发挥他应由的价值。我调研下来发现最关键的痛点就是:不知道该怎么写Prompt可以让ChatGPT输出期望的回答。 哎吆,这不正是撞…...
高精度定位系统中的关键技术:GGA、EHP、RTMC、IMU、GNSS、INS 和 RTK 的协同工作
文章目录 0. 概述1. GGA:标准的定位数据格式2. EHP:增强高度精度3. RTMC:实时监控与控制4. IMU 和 INS:惯性测量和导航系统5. GNSS:全球导航卫星系统6. RTK:实时动态差分定位7. 各技术的融合与协同GPS 数据…...
Spring3~~~
目录 多例 后置处理器BeanPostProcessor XML配置 通过注解 AOP与后置处理器 JdbcTemplate jdbc.properties jdbc.xml Test 具名参数 DAO 声明式事务 GoodsDao GoodsService xml 传播机制 种类 隔离级别 超时回滚 如果是普通的java项目,xml文件放…...
微服务CI/CD实践(五)Jenkins Docker 自动化构建部署Java微服务
微服务CI/CD实践系列: 微服务CI/CD实践(一)环境准备及虚拟机创建 微服务CI/CD实践(二)服务器先决准备 微服务CI/CD实践(三)Jenkins部署及环境配置 微服务CI/CD实践(四)…...
泰州高新区法院多层面强化固定资产管理
固定资产管理是法院的一项基础性工作,法院经费支出相当一部分用于固定资产的购置,为了提高固定资产使用质效,为执法办案提供坚实的保障,高新区法院积极探索科学合理的固定资产管理策略,更新管理思想,完善管…...
JDBC简介与应用:Java数据库连接的核心概念和技术
简短介绍 JDBC 及其重要性。 简短介绍 JDBC JDBC(Java Database Connectivity)是一种用于执行 SQL 语句的 Java API 并且独立于特定的数据库厂商。它允许开发者以一种标准的方式从 Java 应用程序中访问关系型数据库,这意味着一旦你掌握了 J…...
倒反天罡!这个AI风格模型可自由训练,还能批量生成同风格图像
在AIGC的新纪元中,模型已晋升为与算力并驾齐驱的生产力核心要素。也有不少用户反馈提到,如何利用神采PromeAI训练属于自己的风格模型?这需求必须安排!神采PromeAI「一致性模型」正式上线! 可自主训练风格化模型&#x…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
