C++(22)--继承和派生

继承和派生

  • 1.基本概念
  • 2.实现公有继承
  • 3.私有继承的例子
  • 4. 继承和组合

《老九学堂C++课程》《C++ primer》学习笔记。《老九学堂C++课程》详情请到B站搜索《老九零基础学编程C++入门》
-------------简单的事情重复做,重复的事情用心做,用心的事情坚持做(老九君)---------------

1.基本概念

面向对象oop–三大重要特性-- 封装、继承、多态

在C++中,代码重用是通过“继承(inheritance)”机制实现的。
在一个已经存在的类的基础上,再建立一个新类。
从已有的类中派生出新类,派生类就继承了原有类(基类)的特征,包括成员和方法(以后函数就叫方法)

通过继承可以完成的功能-可升级可维护

  1. 在已有类的基础上增加新的功能,对于数组类,可以添加数学计算–排序
  2. 给类添加数据成员,对于字符串类,可以派生类,并添加制定成员表示颜色。
  3. 修改类的方法,对于普通英雄,可以派生出拥有更丰富的技能的近战英雄类

注意:
继承机制只需要提供新的特性,甚至不需要访问源码就可以派生出类
允许在不公开的情况下将自己的类分发给他人,同时允许他们在类中添加新的特性。

程序升级和扩展–非常忌讳的是,修改原有的代码。原来的代码测试通过了,测试实际是一件非常困难的事。

开发一款RPG(Role-playing Gam)游戏
游戏职业:坦克,战士,刺客,法师,射手,辅助

1.0 版本:战士,法师
直接定义英雄类:战士类,法师类–存在相同属性和方法。
把相同的成员和方法封装成基类。

注意:
1.派生类对象存储了基类的数据成员
2.派生类对象可以调用基类的非私有函数
3.派生类需要自己的构造方法
4.派生类根据需要增加额外的成员和方法

继承的继承:称为直接基类和间接基类。

父类的的成员和方法的公有,私有,和受保护三种属性的访问权限:
1.公有权限下,自己和派生类,以及外部都能访问
2.私有权限下,只有自己访问,派生类和外部都无法访问
3.受保护权限下,自己和派生类可以访问,外部无法访问
继承分为公有继承,私有继承,受保护继承。三种方式继承之后子类权限的变化

基类成员公有继承私有继承保护继承
公有公有私有受保护
受保护受保护私有受保护
私有不被继承不被继承不被继承

全部继承,不封装基类–公有继承(除了基类的私有成员不继承,其他都是权限不变的继承)is a 关系。
全部继承,完全封装基类–私有继承(庶出,除了基类的私有成员不继承,其他成员继承后权限改成私有) has a关系。使用包含来实现has a ,用继承来实现有点抽象。
全部继承,有选择封装基类–受保护(除了基类的私有成员不继承,其他成员继承后权限被改为受保护模式)

灵活运用面向对象思想的重要体现。
不管使用哪一种继承,派生类都不能访问基类里的私有成员,除非改成protected.

class Emperor
{
private:string[] bueaties; // 后宫佳丽double silvers;    // 私房钱
protected:string palace; 	   // 宫殿名称
publicEmperor();~Emperor();string reignTile; 	// 年号
}
// 子类的继承关系,非实际代码
class FourthSon:public Emperor
{
// 父类私有成员不可见,
protected:string palace; 		//宫殿名称
public:FourthSon();~FourthSon();string reignTile;  	// 年号
}
class ThirteenSon:protected Emperor
{
protected: // 外人访问不了,只有自己,友元,以及子类能够访问。string reignTile; 	// 年号string palace; 		// 宫殿名称
public:ThirteenSon();~ThirteenSon();
}
class SecondSon: private Emperor
{
private:    //仅作说明,只有自己访问string palace;		//宫殿名称string reignTile; 	// 年号
piblic:SecondSon();~SecondSon();
}

2.实现公有继承

掌握公有继承,了解私有继承和受保护继承。
满足is a 关系的可以用继承。
clion 还不会写配置文件,类图生成

类对象在内存中的存储情况

  1. 在没有继承关系时的内存模型
    a)对象的成员变量存在堆内存区/栈内存区,代码存储在公有的成员函数代码区。所有的对象共同享有一段函数代码
    b)如果使用sizeof 求类所占空间的大小,只是计算了成员变量的大小,并没有把成员函数也包含在内。
  2. 有继承关系时的内存模型
    a)派生类的内存模型看成是基类成员变量和新增成员变量的总和,所有的成员函数仍然共有另一个区域–代码区。

创建的时候先初始化基类再初始化派生类
释放时先释放派生类再释放基类

demo1: Warrior 公有继承

//main.cpp
#include <iostream>
#include <string>
#include "Hero.h"
#include "Warrior.h"using namespace std;
void HeroTest();
void WarriorTest();
int main()
{// HeroTest();WarriorTest();
}
void HeroTest()
{Hero hero1;cout << hero1 << endl;hero1.Move();Hero * hero2 = new Hero("测试英雄2",999,5000,5000);cout << *hero2 << endl;hero2->Move();//(*hero2).Move();      // 等价调用
}
void WarriorTest(){Warrior warrior1;// 情况1:派生类中没有重新实现move方法,调用父类方法// 情况2:派生类中重新实现move方法,调用子类实现的该方法warrior1.Move();cout << warrior1 << endl;Hero * hero = new Warrior;  // 基类指针指向了派生类--标准的多态hero->Move();               // 调用基类的实现delete hero;}
//Hero.h
//
// Created by 陈莹莹 on 2021/3/15.
//#ifndef CHAPTER13_1_HERO_H
#define CHAPTER13_1_HERO_H#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
using namespace std;
class Hero
{
private:string m_NickName;int m_Level;int m_MaxLife;int m_CurrLife;int x;int y;public:Hero();Hero(const string& nickName);Hero(const string& nickName, int level);Hero(const string& nickName, int level, int maxLife, int currLife);void Move();friend ostream& operator<<(ostream& out, const Hero& hero);// friend ostream& operator<<(ostream& out, const* hero);string GetNickName() const{return m_NickName;}int GetLevel() const{return m_Level;}int GetMaxLife() const{return m_MaxLife;}int GetCurrLife() const{return m_CurrLife;}void SetNickName(const string & nickName){this->m_NickName = nickName;}void SetLevel(int level);void SetMaxLife(int maxLife);void SetCurrLife(int currLife);void operation1();
};
#endif //CHAPTER13_1_HERO_H
//Hero.cpp
//
// Created by 陈莹莹 on 2021/3/15.
//#include "Hero.h"
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "Hero.h"
using namespace std;Hero::Hero() : m_NickName("默认英雄"),m_Level(1),m_MaxLife(100),m_CurrLife(100)
{cout << "调用了Hero的默认构造" << endl;
}
//Hero::Hero(const string& nickName):m_NickName(nickName),m_Level(1),m_MaxLife(100),m_CurrLife(100)
//{
//
//}
Hero::Hero(const string& nickName):Hero(nickName,1,100,10)
{cout << "调用了Hero 一个参数版本的构造" << endl;
}
Hero::Hero(const string& nickName, int level):Hero(nickName, level,100,10)
{cout << "调用了Hero 两个参数版本的构造" << endl;
}
Hero::Hero(const string& nickName, int level, int maxLife, int currLife):m_NickName(nickName),m_Level(level),m_MaxLife(maxLife),m_CurrLife(currLife)
{cout << "调用了Hero 四个参数版本的构造" << endl;
}
void Hero::Move()
{// 默认移动cout << "普通英雄" << m_NickName << "正在奔跑在艾泽拉斯大陆上" << endl;
}
ostream& operator<<(ostream& out, const Hero& hero){out << "昵称:" << hero.GetNickName() << "\n";out << "等级:" << hero.GetLevel() << "\n";out << "最大生命:" << hero.GetMaxLife() << "\n";out << "当前生命:" << hero.GetCurrLife() ;return out;
}
void Hero::operation1()
{
}
//Warrior.h
//
// Created by 陈莹莹 on 2021/3/16.
//
#ifndef CHAPTER13_1_WARRIOR_H
#define CHAPTER13_1_WARRIOR_H
#include "Hero.h"
// 共有继承-体现了is a 关系
class Warrior : public Hero{
private:int m_PhysicalAttack;
public:Warrior();Warrior(const string& nickName, int phyAttack);void Move();  // 在派生类中实现派生类版本的move方法~Warrior();
};
#endif //CHAPTER13_1_WARRIOR_H
//Warrior.cpp
//
// Created by 陈莹莹 on 2021/3/16.
//
#include "Warrior.h"
Warrior::Warrior() :Hero("默认构造",1,100,100)
{
}
Warrior::Warrior(const string& nickName, int phyAttack):Hero(nickName,1,100,100),m_PhysicalAttack(phyAttack)
{
}
void Warrior::Move()
{// m_NickName没办法过呀,不能访父类的私有属性,需要在将父类中私有成员改为受保护成员//cout << "战士《" << m_NickName << "》"<< "背着一大堆近战武器正在前进。。。"<< endl;cout << "战士《" << GetNickName() << "》"<< "背着一大堆近战武器正在前进。。。"<< endl;
}
Warrior::~Warrior()
{
}

有关基类,派生类构造

  1. 实例化派生类对象时,首先会创建基类对象(调用基类构造)
  2. 派生类构造应通过成员初始化列表将基类信息传递给基类构造
  3. 应该在派生类构造中初始化派生类新增的数据成员

派生类与基类之间特殊关系小结
1.派生类可以使用基类的非私有成员函数(public和protect)

2.基类指针可以在不进行显示类型转换的情况下指向派生类对象

Warrior warrior1("诸葛达摩", 10, 100, 100);
Hero& refHero = warrior1; // 基类引用指向派生类,
Hero* ptrHero = &warrior1; // 基类指针指向派生类对象
Warrior& warrior2 = (Warrior)refHero;  // 父类引用/指针需要强制转换成子类引用/指针(前提:父类指针指向子类对象)
//不可以将基类对象的地址赋给派生类引用和对象,即不能进行逆操作

3.可以将派生类对象赋值给基类对象,程序会使用隐式重载赋值运算符

Hero hero = warrior;
hero.move();   //调用父类方法

3.私有继承的例子

没讲完呀,暂且收一收好了

//main.cpp
#include <iostream>
#include "Teacher.h"
void TeacherTest(){Teacher teacher1(8000);// 名字设置没有写完
}
int main()
{TeacherTest();return 0;
}
//Teacher.h
//
// Created by 陈莹莹 on 2021/3/21.
//#ifndef CHAPTER13_1_TEACHER_H
#define CHAPTER13_1_TEACHER_H
#include <iostream>
#include <string>
using namespace std;
/** 用来演示私有继承的其中一种用法* 实现组合关系,只能组合一个属性不能组合两个属性* Teacher类中拥有string类型的成员name* */class Teacher :private string{    // teacher 中拥有string类型的成员
private:double salary;                // 工资public:Teacher();Teacher(int _salary) : salary(_salary){}double GetSalary(){return salary;}void SetSalary(double salary){this->salary = salary;}// 难点const string& GetName() const{/** Teacher类是由string 类私有派生而来,所以,可以使用强制类型转换,将Teacher类转换成string类* 为了避免调用构造函数创建新的对象,所以强制转换成了string 的引用类型返回* 本方法返回一引用,指向调用本方法的Teacher 对象中继承而来的string对象* */return (const string&)*this;      //强转}//using string::length();   //将字符串方法声明为本类的公有方法/*返回当前教师类对象姓名的字符串长度*/int GetLenght(){return string::length();}~Teacher();string nickName;             // 使用组合关系实现比较简单的has-a 关系protected:};
#endif //CHAPTER13_1_TEACHER_H

4. 继承和组合

一张脸由多个类组合而成,头发的不同总类从父类头发那里继承而来。

继承是is a 纵向关系–狗是哺乳动物,战士是英雄,橘猫是宠物–
组合是has a 横向关系–学生有书包,战士有武器,

继承是C++与C最重要的区别,虽然C++也可以用C语言的编程习惯。

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

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

相关文章

Python- 解决PIP下载安装速度慢

对于Python开发用户来讲&#xff0c;PIP安装软件包是家常便饭。但国外的源下载速度实在太慢&#xff0c;浪费时间。而且经常出现下载后安装出错问题。所以把PIP安装源替换成国内镜像&#xff0c;可以大幅提升下载速度&#xff0c;还可以提高安装成功率。 国内源&#xff1a; …

leetcode102 二叉树的层次遍历

给定一个二叉树&#xff0c;返回其按层次遍历的节点值。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回其层次遍历结果&#xff1a; [ [3], [9,20], [15…

Windows Git客户端搭建

最近开始做Windows 开发&#xff0c;所以找了一些windows下安装git的教程 本文环境&#xff1a; 操作系统&#xff1a;Windows XP SP3 Git客户端&#xff1a;TortoiseGit-1.8.16.0-32bit 一、安装Git客户端 全部安装均采用默认&#xff01; 1. 安装支撑软件 msysgit: http://ms…

C++(23)--多态性与虚函数

多态性与虚函数1.静态多态-重载2.动态多态-重写2.1 向上转换/向下转换3.虚函数的工作原理4.纯虚函数和抽象类5.补充项目(都市浮生记)-卒《老九学堂C课程》学习笔记。《老九学堂C课程》详情请到B站搜索《老九零基础学编程C入门》-------------简单的事情重复做&#xff0c;重复的…

如何在Appscale下发布自己的应用(一)

本篇文章主要讲如何在本地搭建appscale环境。由于国内的信息资源有限&#xff0c;很多重要的论坛被墙了&#xff0c;所以遇到不少麻烦&#xff0c;由于最近一段时间vpn也被封掉了&#xff0c;我只能通过特殊渠道方法来翻墙查阅资料&#xff0c;走了不少弯路。 1.先说系统和环境…

总结了线程安全性的二十四个精华问题

1、对象的状态&#xff1a;对象的状态是指存储在状态变量中的数据&#xff0c;对象的状态可能包括其他依赖对象的域。在对象的状态中包含了任何可能影响其外部可见行为的数据。 2、一个对象是否是线程安全的&#xff0c;取决于它是否被多个线程访问。这指的是在程序中访问对象的…

如何在Appscale下发布自己的应用(二)

本文开始讲如何发布自己的app应用到appscle上 建好appscle网站后&#xff0c;可以在命令行通过 appscle deploy apppathname 来发布自己应用。 除了用命令行提交应用之外&#xff0c;还可以通过appscale的网站直接提交&#xff0c;选择 upload application->选择上传文件-&g…

Python模块(7)-SciPy 简易使用教程

SciPy 简易使用教程1. 符号计算2. 函数向量化3. 波形处理scipy.signal3.1 滤波器3.2 波峰定位基于numpy的一个高级模块&#xff0c;为数学&#xff0c;物理&#xff0c;工程等方面的科学计算提供无可替代的支持。 做重要的思想是&#xff1a;符号计算和函数向量化 1. 符号计算…

Xcode的Architectures和Valid Architectures的区别

目录[-] Xcode的Architectures和Valid Architectures的区别 Architectures Valid Architectures 原因解释如下&#xff1a; 参考1&#xff1a; 所有IOS设备详情列表 List of iOS devices - Wikipedia, the free encyclopedia 参考2&#xff1a; iOS 7: 如何为iPhone 5S编译64位…

Python模块(8)-sklearn 简易使用教程

sklearn 简易使用教程1.scikit-learn的数据集2.scikit-learn 的训练和预测scikit-learn 是在Numpy,SciPy,Matplotlib三个模块上编写的&#xff0c;数据挖掘和数据分析的一个简单有效的工具。scikit-learn包括6大功能&#xff1a;分类&#xff0c;回归&#xff0c;聚类&#xff…

如何发布GAE的应用(一)

安装googleSDK的环境&#xff1a; 1 下载安装包从官网下载 https://cloud.google.com/sdk/downloads -> https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-170.0.0-windows-x86_64-bundled-python.zip 2 如果本地安装了python&#xff0c;直…

leetcode887 鸡蛋掉落

你将获得 K 个鸡蛋&#xff0c;并可以使用一栋从 1 到 N 共有 N 层楼的建筑。 每个蛋的功能都是一样的&#xff0c;如果一个蛋碎了&#xff0c;你就不能再把它掉下去。 你知道存在楼层 F &#xff0c;满足 0 < F < N 任何从高于 F 的楼层落下的鸡蛋都会碎&#xff0c;…

Docker 的日志相关整理

1 Docker daemon日志的位置 Docker daemon日志的位置&#xff0c;根据系统不同各不相同。 Ubuntu - /var/log/upstart/docker.logBoot2Docker - /var/log/docker.logDebian GNU/Linux - /var/log/daemon.logCentOS - /var/log/daemon.log | grep dockerFedora - journalctl -u…

PaperNotes(15)-图神经网络、PyG极简版入门笔记

图神经网络概况1.GNN,GCN,GE的区别2.图卷积的通式--矩阵该如何作用2.1实现12.2实现22.3实现33.PyTorch geometric3.1 PyG内置数据集3.1.1ENZYMES dataset3.1.2Cora3.2 PyG自定义数据集3.2.1Data构建简单的图结构3.2.2 Dataset3.2.3 InMemoryDataset一文读懂图卷积GCN(https://z…

leetcode76 最小覆盖子串

给你一个字符串 S、一个字符串 T&#xff0c;请在字符串 S 里面找出&#xff1a;包含 T 所有字母的最小子串。 示例&#xff1a; 输入: S "ADOBECODEBANC", T "ABC" 输出: "BANC" 说明&#xff1a; 如果 S 中不存这样的子串&#xff0c;则返…

Unity的匹配系统

这个匹配系统是指一个玩家&#xff0c;可以创建一个自己随意命名的房间&#xff0c;然后其他玩家可以通过联网去搜索房间&#xff0c;然后加入房间一起游戏 我先讲讲怎么使用这个匹配系统&#xff1a; 在运行游戏后&#xff0c;因为添加了Network Manager HUD组件&#xff0c;所…

PaperNotes(16)-图神经网络GNN简史、不动点建模-笔记

图神经网络简史、简介1.图神经网络简史2.图神经网络--学习过程3.图神经网络--理论基础4.图神经网络的局限5.GNN,RNN,GGNN6.小结阅读笔记&#xff1a;从图(Graph)到图卷积(Graph Convolution)&#xff1a;漫谈图神经网络模型 (一)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Matchmaker

Unity的多玩家网络功能包含了玩家在因特网上互相玩而不需要公共IP地址的服务。用户可以创建游戏,获取活动游戏列表;加入并退出游戏。当在internet上玩时,网络流量将通过云中的Unity,而不是直接在客户端之间进行。这就避免了防火墙和NATs的问题,几乎可以在任何地方玩游戏。 …

PaperNotes(17)-图卷积神经网络GCN-笔记

图卷积神经网络GCN-笔记1.卷积是什么2.图卷积的源起3.空域卷积3.1消息传递网络MPNN3.2 图采样与聚合GraphSage4.频域卷积5.图结构的序列化-Patch-SAN从图(Graph)到图卷积(Graph Convolution)&#xff1a;漫谈图神经网络模型 (二)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 标签

摘录某个工程的 web.xml 文件片段&#xff1a;访问顺序为1—>2—>3—>4&#xff0c;其中2和3的值必须相同。 url-pattern 标签中的值是要在浏览器地址栏中输入的 url&#xff0c;可以自己命名&#xff0c;这个 url 访问名为 servlet-name 中值的 servlet&#xff0c;两…