探索C++三大特性--C++ 继承详解:从概念到高级用法

一、继承的概念

继承(Inheritance)机制是面向对象程序设计中最重要的手段之一。通过继承,我们可以在已有类的基础上进行扩展,增加新的方法和属性,从而创建新的类,这些新类被称为派生类(Derived Class)【14†source】。继承的主要目的是实现代码复用,使得相似功能代码的编写更加简洁高效,并使系统具有更好的可维护性。

1.1 没有继承时的问题

在没有继承的情况下,我们可能会设计多个功能相似的类,这些类中含有相同的成员变量和成员函数。例如,我们设计了两个类:——StudentTeacher,它们都拥有姓名、地址、电话等成员变量,以及身份认证的成员函数。这导致了代码的冗余和维护困难。

class Student {
public:// 身份认证void identity() {// ...}// 学习void study() {// ...}
protected:string _name = "peter"; // 姓名string _address;         // 地址string _tel;             // 电话int _age = 18;           // 年龄int _stuid;              // 学号
};class Teacher {
public:// 身份认证void identity() {// ...}// 授课void teaching() {// ...}
protected:string _name = "张三";   // 姓名int _age = 18;           // 年龄string _address;         // 地址string _tel;             // 电话string _title;           // 职称
};

如上代码中,StudentTeacher类中存在大量重复成员变量和函数,这种冗余不仅增加了代码量,也使得代码维护变得复杂。

1.2 使用继承的改进

通过继承,我们可以将公共的成员变量和函数提取到一个基类(Base Class)中,例如Person类,然后让StudentTeacher类继承Person类,从而减少重复代码。

class Person {
public:// 身份认证void identity() {cout << "void identity()" << _name << endl;}
protected:string _name = "张三";  // 姓名string _address;        // 地址string _tel;            // 电话int _age = 18;          // 年龄
};class Student : public Person {
public:// 学习void study() {// ...}
protected:int _stuid;             // 学号
};class Teacher : public Person {
public:// 授课void teaching() {// ...}
protected:string title;           // 职称
};

通过上述改进,StudentTeacher类继承了Person类,公共成员被提取到基类中,这样可以减少重复代码,提高代码的可维护性。

二、继承的定义与访问控制

2.1 继承的定义方式

在C++中,继承是通过指定继承方式来实现的,常见的继承方式有三种:

  • public 继承:基类的publicprotected成员在派生类中保持相同的访问控制。

  • protected 继承:基类的public成员在派生类中变为protected,而protected成员保持不变。

  • private 继承:基类的所有非private成员在派生类中都变为private

class Person {
public:void Print() {cout << _name << endl;}
protected:string _name; // 姓名
};// public 继承
class Student : public Person {
protected:int _stunum; // 学号
};

在实际使用中,public继承是最常见的方式,因为它可以保持基类成员的可访问性。而protectedprivate继承较少使用,因为它们限制了派生类对基类成员的访问,从而降低了代码的扩展性和维护性。

2.2 基类成员的访问控制

在继承体系中,基类的private成员在派生类中是不可见的,这意味着派生类对象无法访问基类中的私有成员。而基类的protected成员则可以在派生类中访问,这使得派生类能够继承和使用这些成员。

class Person {
protected:string _name; // 姓名
private:int _age;    // 年龄
};class Student : public Person {
public:void Print() {cout << _name << endl; // 可以访问基类的受保护成员// cout << _age;      // 无法访问基类的私有成员}
protected:int _stunum; // 学号
};

三、继承中的作用域与隐藏规则

3.1 成员隐藏

在继承体系中,如果派生类和基类中存在同名的成员,那么基类的成员会被隐藏。此时,派生类只能访问自己的成员,而不能直接访问基类的同名成员。

class Person {
protected:int _num = 111; // 身份证号
};class Student : public Person {
public:void Print() {cout << "身份证号: " << Person::_num << endl;cout << "学号: " << _num << endl;}
protected:int _num = 999; // 学号
};

在上面的例子中,Student类中的_num隐藏了Person类中的同名成员,因此如果想访问基类中的_num,需要使用Person::_num来显式指定。

四、派生类的默认成员函数

在派生类中,默认的成员函数(如构造函数、析构函数、拷贝构造函数、赋值运算符等)会自动生成,并且派生类会调用基类的相应成员函数来初始化基类部分。

class Person {
public:Person(const char* name = "peter") : _name(name) {cout << "Person()" << endl;}~Person() {cout << "~Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person {
public:Student(const char* name, int num) : Person(name), _num(num) {cout << "Student()" << endl;}~Student() {cout << "~Student()" << endl;}
protected:int _num; // 学号
};int main() {Student s1("jack", 18);return 0;
}

在上面的代码中,Student类的构造函数和析构函数在执行时会首先调用基类Person的构造函数和析构函数,这样能够确保基类部分正确初始化和清理。

五、多继承与菱形继承问题

5.1 多继承

C++ 支持多继承,即一个类可以继承自多个基类。然而,多继承可能会导致菱形继承问题,即多个基类中有相同的成员,导致派生类中有两份相同的成员拷贝。

class Person {
public:string _name; // 姓名
};class Student : public Person {
protected:int _num; // 学号
};class Teacher : public Person {
protected:int _id; // 职工编号
};class Assistant : public Student, public Teacher {
protected:string _majorCourse; // 主修课程
};

在上述代码中,Assistant类同时继承自StudentTeacher,由于这两个基类都继承自Person,因此Assistant类中存在两份_name成员,这就产生了数据冗余和访问二义性的问题。

5.2 虚继承解决菱形继承问题

为了避免菱形继承带来的问题,我们可以使用虚继承。通过虚继承,派生类只会保留一份基类的成员。

class Person {
public:string _name; // 姓名
};class Student : virtual public Person {
protected:int _num; // 学号
};class Teacher : virtual public Person {
protected:int _id; // 职工编号
};class Assistant : public Student, public Teacher {
protected:string _majorCourse; // 主修课程
};int main() {Assistant a;a._name = "peter"; // 没有二义性return 0;
}

通过虚继承,Assistant类中只会有一份Person类的成员,避免了数据冗余和访问的二义性。

六、继承与组合的选择

在面向对象设计中,继承表示一种is-a的关系,而组合表示一种has-a的关系。优先使用组合而不是继承可以降低类之间的耦合度,提高代码的灵活性和可维护性。

class Tire {
protected:string _brand = "Michelin";  // 品牌size_t _size = 17;            // 尺寸
};class Car {
protected:string _colour = "白色";       // 颜色Tire _t1, _t2, _t3, _t4;      // 四个轮胎
};class BMW : public Car {
public:void Drive() { cout << "驾驶宝马车" << endl; }
};

在上述代码中,Car类通过组合方式包含了四个轮胎对象Tire,这种设计更符合逻辑上的has-a关系。在实际设计中,优先使用组合可以减少代码的耦合性,增强代码的复用性和灵活性。

总结

继承是C++中实现代码复用和扩展的重要手段,它可以简化代码结构,减少冗余代码,增强代码的可维护性。然而,在使用继承时,我们需要遵循一些设计原则,避免滥用继承导致代码复杂化。同时,理解继承与组合之间的差异,合理选择使用继承或组合,对于编写高质量的面向对象代码非常重要。

希望这篇博客能够帮助大家深入理解C++继承的概念和使用方法。欢迎大家在实际项目中应用这些知识,编写出更加优雅和高效的代码。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

VBA技术资料MF223:从文件添加新模块

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

利用RAGflow和LM Studio建立食品法规问答系统

前言 食品企业在管理标准、法规&#xff0c;特别是食品原料、特殊食品法规时&#xff0c;难以通过速查法规得到准确的结果。随着AI技术的发展&#xff0c;互联网上出现很多AI知识库的解决方案。 经过一轮测试&#xff0c;找到问题抓手、打通业务底层逻辑、对齐行业颗粒度、沉…

路径规划——RRT*算法

路径规划——RRT*算法 算法原理 RRT Star 算法是一种渐近最优的路径规划算法&#xff0c;它是 RRT 算法的优化版本。RRT Star 算法通过不断地迭代和优化&#xff0c;最终可以得到一条从起点到目标点的最优路径。 在学习RRT Star 算法之前最好先学习一下RRT原始算法&#xff1…

Java——并发工具类库线程安全问题

摘要 本文探讨了Java并发工具类库中的线程安全问题&#xff0c;特别是ThreadLocal导致的用户信息错乱异常场景。文章通过一个Spring Boot Web应用程序示例&#xff0c;展示了在Tomcat线程池环境下&#xff0c;ThreadLocal如何因线程重用而导致异常&#xff0c;并讨论了其他并发…

网络编程套接字

前言&#xff1a; 认识了网络&#xff0c;我们就应该考虑一下如何编程实现不同主机上的应用进程之间如何进行双向互通的端点。 套接字&#xff08;Socket&#xff09;是网络编程的一种基本概念&#xff0c;套接字是应用程序通过网络协议进行通信的接口&#xff0c;是操作系统提…

计算机网络:运输层 —— TCP 的拥塞控制

文章目录 TCP的拥塞控制拥塞控制的基本方法流量控制与拥塞控制的区别拥塞控制分类闭环拥塞控制算法 TCP的四种拥塞控制方法&#xff08;算法&#xff09;窗口慢开始门限慢开始算法拥塞避免算法快重传算法快恢复算法 TCP拥塞控制的流程TCP拥塞控制与网际层拥塞控制的关系 TCP的拥…

vue学习第8章(vue的购物车案例)

&#x1f389;&#x1f389;&#x1f389;欢迎来到我的博客,我是一名自学了2年半前端的大一学生,熟悉的技术是JavaScript与Vue.目前正在往全栈方向前进, 如果我的博客给您带来了帮助欢迎您关注我,我将会持续不断的更新文章!!!&#x1f64f;&#x1f64f;&#x1f64f; 文章目录…

【SpringBoot】什么是Maven,以及如何配置国内源实现自动获取jar包

前言 &#x1f31f;&#x1f31f;本期讲解关于Maven的了解和如何进行国内源的配置~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f3…

【Linux】:进程信号(详谈信号捕捉 OS 运行)

✨ 来去都是自由风&#xff0c;该相逢的人总会相逢 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞…

七、利用CSS和多媒体美化页面的习题

题目一&#xff1a; 利用CSS技术&#xff0c;结合表格和列表&#xff0c;制作并美化 “ 翡翠阁 ”页面。运行效果如下 运行效果&#xff1a; 代码 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title>翡翠阁</title>&…

动态规划 —— 子数组系列-等差数列划分

1. 等差数列划分 题目链接&#xff1a; 413. 等差数列划分 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/arithmetic-slices/description/ 2. 算法原理 状态表示&#xff1a;以某一个位置为结尾或者以某一个位置为起点 dp[i]表示&#xff1a;以i位置为…

vue使用List.reduce实现统计

需要对集合的某些元素的值进行计算时&#xff0c;可以在计算属性中使用forEach方法 1.语法&#xff1a;集合.reduce ( ( 定义阶段性累加后的结果 , 定义遍历的每一项 ) > 定义每一项求和逻辑执行后的返回结果 , 定义起始值 ) 2、简单使用场景&#xff1a;例如下面…

TensorFlow 2.0 windows11 GPU 训练环境配置

前言 在一切开始之前&#xff0c;请确保你的cmd命令行和powershell命令行可以正常打开。如果不能&#xff0c;建议重装系统。我不确定这是否会影响你最终的结果&#xff0c;毕竟windows的坑太多了。 安装顺序&#xff1a;visual studio -> cuda -> cudnn -> python…

MyISAM和InnoDB介绍及切换存储引擎方法

MyISAM 和 InnoDB 都是 MySQL 数据库管理系统中常用的存储引擎&#xff08;Storage Engine&#xff09;。存储引擎决定了数据库如何存储、读取、更新数据以及如何管理事务、锁定等操作。 1. MyISAM 存储引擎 MyISAM 是 MySQL 的默认存储引擎之一&#xff0c;尤其是在早期版本…

什么是嵌入式?

目录 一、什么是嵌入式 二、嵌入式系统的特点 &#xff08;一&#xff09;专用性与隐蔽性 &#xff08;二&#xff09;高可靠性与实时性 &#xff08;三&#xff09;资源固定与小型化 三、嵌入式系统的发展历史 &#xff08;一&#xff09;20 世纪 60 年代早期雏形 &am…

在几分钟内将数据从 Oracle 迁移到 ClickHouse

ClickHouse 是一个开源的面向列的数据库管理系统。它在实时数据处理方面的出色性能显着增强了数据分析和业务洞察力。将数据从 Oracle 迁移到 ClickHouse 可以释放数据在决策中的力量&#xff0c;这是单独使用 Oracle 无法实现的。 本教程介绍如何使用 BladePipe 将数据从 Orac…

Linux网络:HTTPS协议

Linux网络&#xff1a;HTTPS协议 加密方式对称加密非对称加密混合加密中间人攻击 证书数据签名CA认证 HTTPSSSL/TSLHTTPS 在HTTP协议中&#xff0c;所有的数据都采用明文的形式传输&#xff0c;这就会导致数据非常容易泄露&#xff0c;只要拿到HTTP报文&#xff0c;就可以窃取各…

(计算机毕设)基于springboot免税商品购物商城的设计与实现

博主可接毕设设计&#xff01;&#xff01;&#xff01; 各种毕业设计源码只要是你有的题目我这里都有源码 基于springboot免税商品购物商城的设计与实现 摘 要 Abstract 第一章 绪论 1.1 课题开发的背景 1.2 课题研究的意义 1.3 研究内容 第二章 系统开发关键技术…

计算机能力挑战赛c语言2024

先看看答题页面长啥样&#xff1a;选择题15道&#xff0c;编程题4道 选择题&#xff08;楼主个人答案&#xff09; 编程题

Java集合HashMap——针对实习面试

目录 Java集合MapHashMap的特性是什么&#xff1f;HashMap和Hashtable的区别&#xff1f;HashMap和HashSet的区别&#xff1f;HashMap和TreeMap的区别&#xff1f;说说HashMap的底层实现什么是hash冲突&#xff1f;有什么办法减少hash冲突&#xff1f;为什么HashMap的容量总是2…