简单aspx网站开发,辽宁建设工程信息网新域名,wordpress取消评论审核,网站建设中的风险风险继承和派生1.基本概念2.实现公有继承3.私有继承的例子4. 继承和组合《老九学堂C课程》《C primer》学习笔记。《老九学堂C课程》详情请到B站搜索《老九零基础学编程C入门》-------------简单的事情重复做#xff0c;重复的事情用心做#xff0c;用心的事情坚持做(老九君)----…
继承和派生1.基本概念2.实现公有继承3.私有继承的例子4. 继承和组合《老九学堂C课程》《C primer》学习笔记。《老九学堂C课程》详情请到B站搜索《老九零基础学编程C入门》-------------简单的事情重复做重复的事情用心做用心的事情坚持做(老九君)---------------1.基本概念
面向对象oop–三大重要特性-- 封装、继承、多态
在C中代码重用是通过“继承(inheritance)”机制实现的。 在一个已经存在的类的基础上再建立一个新类。 从已有的类中派生出新类派生类就继承了原有类基类的特征包括成员和方法以后函数就叫方法
通过继承可以完成的功能-可升级可维护
在已有类的基础上增加新的功能对于数组类可以添加数学计算–排序给类添加数据成员对于字符串类可以派生类并添加制定成员表示颜色。修改类的方法对于普通英雄可以派生出拥有更丰富的技能的近战英雄类
注意 继承机制只需要提供新的特性甚至不需要访问源码就可以派生出类 允许在不公开的情况下将自己的类分发给他人同时允许他们在类中添加新的特性。
程序升级和扩展–非常忌讳的是修改原有的代码。原来的代码测试通过了测试实际是一件非常困难的事。
开发一款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 还不会写配置文件类图生成
类对象在内存中的存储情况
在没有继承关系时的内存模型 a对象的成员变量存在堆内存区/栈内存区代码存储在公有的成员函数代码区。所有的对象共同享有一段函数代码 b如果使用sizeof 求类所占空间的大小只是计算了成员变量的大小并没有把成员函数也包含在内。有继承关系时的内存模型 a)派生类的内存模型看成是基类成员变量和新增成员变量的总和所有的成员函数仍然共有另一个区域–代码区。
创建的时候先初始化基类再初始化派生类 释放时先释放派生类再释放基类
demo1: Warrior 公有继承
//main.cpp
#include iostream
#include string
#include Hero.h
#include Warrior.husing 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.派生类可以使用基类的非私有成员函数(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语言的编程习惯。