C++基础(17)——继承
目录
1.继承的概述
1.1概念
1.2继承的基本用法
1.3继承的好处
1.4语法
2.继承方式
2.1继承语法
2.2继承方式
3.继承中的构造与析构顺序
4.继承同名成员处理方式
4.1继承同名成员属性处理方式
4.2继承同名成员函数处理方式
5.同名静态成员处理
6.多继承语法
7.菱形继承案例
7.1菱形继承概念
1.继承的概述
1.1概念
继承是面向对象三大特性之一。我们发现在定义类的时候,下级别的成员除了拥有上一级别的的共性,还有自己的特性,这时候我们可以考虑使用继承的技术来减少重复的代码。
1.2继承的基本用法
例如我们看到很多的网站中,都有公共的头部、公共的底部、甚至公共的左侧列表,只有中心内容不同,接下来我们分别利用普通写法和继承的写法来实现网页中的内容,看一下继承存在的意义以及好处。
#include<iostream>
using namespace std;class java {//java网站类
public:void header() {cout << "首页、公开课、登录、注册……(公共头部)" << endl;}void foter() {cout << "帮助中心、交流合作、站内地图……(公共底部)" << endl;}void left(){cout << "Java、python、C++……(公共分类列表)" << endl;}void content() {cout << "java学科视频" << endl;}
};//Python页面
class Python {//java网站类
public:void header() {cout << "首页、公开课、登录、注册……(公共头部)" << endl;}void foter() {cout << "帮助中心、交流合作、站内地图……(公共底部)" << endl;}void left() {cout << "Java、python、C++……(公共分类列表)" << endl;}void content() {cout << "Python学科视频" << endl;}
};//C++学习页面
class Cpp{//java网站类
public:void header() {cout << "首页、公开课、登录、注册……(公共头部)" << endl;}void foter() {cout << "帮助中心、交流合作、站内地图……(公共底部)" << endl;}void left() {cout << "Java、python、C++……(公共分类列表)" << endl;}void content() {cout << "C++学科视频" << endl;}
};void test02() {java ja;cout << "java下载视频页面如下" << endl;ja.header();ja.foter();ja.left();ja.content();cout << "-----------------------" << endl;cout << "Python下载视频页面如下" << endl;Python py;py.header();py.foter();py.left();py.content();cout << "-----------------------" << endl;cout << "C++下载视频页面如下" << endl;Cpp cp;cp.header();cp.foter();cp.left();cp.content();
}void main() {test02();
}
可以看到,代码没有问题,但是有太多的冗余代码,这样看起来太low。所以我们可以考虑使用继承的方式:
class BasePage {//公共的界面
public:void header() {cout << "首页、公开课、登录、注册……(公共头部)" << endl;}void foter() {cout << "帮助中心、交流合作、站内地图……(公共底部)" << endl;}void left() {cout << "Java、python、C++……(公共分类列表)" << endl;}
};//Java页面
class Java :public BasePage {//继承公共页面
public:void content() {cout << "Java学科视频" << endl;}
};//Python页面
class Python :public BasePage {//继承公共页面
public:void content() {cout << "Python学科视频" << endl;}
};//C++页面
class Cpp :public BasePage {//继承公共页面
public:void content() {cout << "C++学科视频" << endl;}
};void test02() {Java ja;cout << "java下载视频页面如下" << endl;ja.header();ja.foter();ja.left();ja.content();cout << "-----------------------" << endl;cout << "Python下载视频页面如下" << endl;Python py;py.header();py.foter();py.left();py.content();cout << "-----------------------" << endl;cout << "C++下载视频页面如下" << endl;Cpp cp;cp.header();cp.foter();cp.left();cp.content();
}void main() {test02();
}
1.3继承的好处
减少重复冗余的代码
1.4语法
class 子类:继承方式 父类 ,如下所示:
子类:也成为派生类,父类也称为基类
2.继承方式
2.1继承语法
class 子类:继承方式 父类
2.2继承方式
- 公共继承
- 保护继承
- 私有继承
解析:
- 子类不能继承父类的私有属性
- 子类如果是公共继承,在父类中是公共的属性在子类中同样是,在父类中是保护继承的属性,在子类中也是如此
- 如果子类是保护继承,父类中的公共属性,在子类中变为保护权限,父类保护,子类也是保护
- 如果子类是私有继承父类中的公共权限和保护权限属性,在子类中都变为私有权限
#include<iostream>
using namespace std;//公共继承
class Base1 {
public:int m_A;
protected:int m_B;
private:int m_C;
};class Son :public Base1 {
public:void func() {m_A = 10;//没有报错说明父类中的公共类成员在子类中依然是公共权限m_B = 10;//没有报错说明父类中的保护类成员在子类中依然是保护权限//m_C = 10;报错了,说明父类中的私有属性,子类拿不到}int m_D;
};void test02() {Son s1;s1.m_A = 100;//m_A是公共权限,类内可以访问,类外也可以访问//s1.m_B = 100;m_B是保护权限,类内可以访问,但是类外不可访问cout << "size of Son =" << sizeof(Son) << endl;
}void main() {test02();
}
我们也可以利用开发人员命令提示工具查看对象模型(VS自带的Developer Command Prompt)
- 查看需要运行的程序在哪个盘,如果在D盘就输入D:就跳转到D盘
- 跳转文件的路径:cd 具体的路径
- 查看对象模型输入:cl /d1 reportSingleClassLayout类名 “文件名”
如下所示:
3.继承中的构造与析构顺序
子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题:父类和子类的构造和析构顺序谁先谁后呢?
#include<iostream>
using namespace std;//继承中的构造与析构的顺序
class Base1 {
public:Base1() {cout << "Base1的构造函数" << endl;}~Base1() {cout << "Base1的析构函数" << endl;}
};class Son :public Base1 {
public:Son() {cout << "Son的构造函数" << endl;}~Son() {cout << "Son的析构函数" << endl;}
};void test01() {//Base1 b;Son s;}void main() {test01();
}
可以看出,继承中的构造与析构顺序如下:
先构造父类,再构造子类,析构的顺序与构造的顺序相反
4.继承同名成员处理方式
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或者父类中的同名的数据?
- 访问子类同名成员 直接访问即可
- 访问父类的同名成员需要加作用域
4.1继承同名成员属性处理方式
#include<iostream>
using namespace std;//继承中的构造与析构的顺序
class Base1 {
public:Base1() {m_A = 100;}int m_A ;
};class Son :public Base1 {
public:Son() {m_A = 200;}int m_A;
};void test01() {Son s;cout << "Son m_A=" <<s. m_A << endl;}void main() {test01();
}
可以看出如果直接访问,m_A是200,说明如果出现同名直接访问是访问的自身的成员。
如果需要拿到父类的成员:
只需要加一个父类的作用域即可访问到同名中父类的属性。
4.2继承同名成员函数处理方式
#include<iostream>
using namespace std;//继承中的构造与析构的顺序
class Base1 {
public:Base1() {m_A = 100;}void func() {cout << "这是base中的函数调用" << endl;}int m_A ;
};class Son :public Base1 {
public:Son() {m_A = 200;}void func() {cout << "这是son中的函数调用" << endl;}int m_A;
};void test01() {Son s;cout << "Son m_A=" <<s. m_A << endl;cout << "Base m_A=" << s.Base1::m_A << endl;
}void test02() {Son s;s.func();//当出现重名调用的还是子类的s.Base1::func();//调用父类的成员函数
}
void main() {test01();test02();
}
5.同名静态成员处理
问题:继承同名的静态成员在子类对象上如何进行访问?
静态成员和非静态成员出现同名,处理方式一样。
- 访问子类同名成员,直接访问即可
- 访问父类同名成员,需要加作用域
静态成员的属性特点:
- 编译阶段分配内存
- 所有对象共享一份数据
- 类内声明,类外要初始化
#include<iostream>
using namespace std;class Base1 {
public:static int m_A ;//类内声明
};
int Base1::m_A = 100;//类外初始化class Son :public Base1 {
public:static int m_A;
};
int Son::m_A = 200;void test01() {Son s;cout << "Son m_A=" << s.m_A << endl;
}
void main() {test01();
}
可以看到直接访问是访问的子类的,要想访问父类需要加一个作用域
访问可以通过对象访问,也可以通过类名访问,如下:
#include<iostream>
using namespace std;class Base1 {
public:static int m_A ;//类内声明
};
int Base1::m_A = 100;//类外初始化class Son :public Base1 {
public:static int m_A;
};
int Son::m_A = 200;void test01() {//通过对象访问Son s;cout << "Son m_A=" << s.m_A << endl;cout << "Base m_A=" << s.Base1::m_A << endl;//通过类名访问cout << "通过类名访问:" << endl;cout << "Son 下 m_A=" << Son::m_A<<endl;cout << "Base 下 m_A=" << Son::Base1::m_A << endl;
}
void main() {test01();
}
继承静态的成员属性以及成员函数的完整代码如下:
#include<iostream>
using namespace std;class Base1 {
public:static void func() {cout << "Base static void func()" << endl;}static int m_A ;//类内声明
};
int Base1::m_A = 100;//类外初始化class Son :public Base1 {
public:static void func() {cout << "Son static void func()" << endl;}static int m_A;
};
int Son::m_A = 200;void test01() {//通过对象访问Son s;cout << "Son m_A=" << s.m_A << endl;cout << "Base m_A=" << s.Base1::m_A << endl;//通过类名访问cout << "通过类名访问:" << endl;cout << "Son 下 m_A=" << Son::m_A<<endl;cout << "Base 下 m_A=" << Son::Base1::m_A << endl;
}void test02() {//通过对象访问cout << "通过对象访问" << endl;Son s;s.func();s.Base1::func();//通过类访问cout << "通过类访问" << endl;Son::func();Son::Base1::func();
}
void main() {test01();cout << "***********************" << endl;test02();
}
6.多继承语法
C++允许一个类继承多个类
语法:class 子类 :继承方式 父类1,继承方式 父类2 ……
注意:多继承可能会引发父类中有同名成员的出现,需要加作用域区分
C++在实际开发中不建议使用多继承
#include<iostream>
using namespace std;class Base1 {
public:Base1() {m_A = 100;}int m_A;
};class Base2 {
public:Base2() {m_B = 200;}int m_B;
};//子类继承Base1和Base2
class Son :public Base1,public Base2{
public:Son() {m_C = 300;m_D = 400;}int m_C;int m_D;
};void test01() {Son s;cout << "sizeof Son=" << sizeof(s) << endl;
}void main() {test01();}
我们可以看看类的结构,具体如何打开的见上一个博客。
我们可以看出size是16,Son这个类,在Base1中继承了m_A在Base2中继承了m_B,自己还有m_C和m_D。
7.菱形继承案例
7.1菱形继承概念
- 两个派生类继承同一个基类
- 又有某个类同时继承两个派生类
- 这种继承称为菱形继承,或者钻石继承
例如:羊和骆驼继承了动物这个类,草泥马这个动物又继承了羊和骆驼这个类,若动作有一个m_A这个属性,那么羊和骆驼也继承了动物类中的m_A,那么草泥马这个类就有两份m_A,而我们只需要一份即可,那怎么办?
#include<iostream>
using namespace std;//动物类
class Animal {int m_Age;
};//羊类
class Sheep:public Animal {};//骆驼类
class Camel:public Animal {};//羊驼类(草泥马类)
class SheepCamel :public Sheep, public Camel {};void test01() {SheepCamel sc;sc.m_Age = 10;
}void main() {test01();}
test01中直接对m_Age=10赋值会出现“SheepCamel m_Age不明确”的错误。所以:当菱形继承,两个父类拥有相同的数据,需要加以作用域区分
那么草泥马(羊驼)的m_Age到底是多少呢,我们只需要一份数据就可以了。我们打出报告可以看到:SheepCamel继承了两个类,一个是Sheep一个是Camel,有两个m_Age,但是我们只需要一个m_Age那么该如何解决呢?
利用虚继承可以解决菱形继承的问题。即为,在继承之前加一个关键字virtual变为虚继承。
#include<iostream>
using namespace std;//动物类
class Animal {
public:int m_Age;
};//利用虚继承解决菱形继承问题,继承之前加上关键词virtual变为虚继承
//Animal类称为虚基类
//羊类
class Sheep:virtual public Animal {};//骆驼类
class Camel:virtual public Animal {};//羊驼类(草泥马类)
class SheepCamel :public Sheep, public Camel {};void test01() {SheepCamel sc;sc.Sheep::m_Age = 10;sc.Camel::m_Age = 28;//当菱形继承,两个父类拥有相同的数据,需要加以作用域区分cout << "sc.Sheep::m_Age = " << sc.Sheep::m_Age << endl;cout << "sc.Camel::m_Age=" << sc.Camel::m_Age << endl;cout << "SheepCamel m_Age=" << sc.m_Age << endl;
}void main() {test01();}
经过修改后发现年龄都变成28了。我们再看看报告:
可以看到与没有加关键词virtual时的结构完全不一样了。可以看到SheepCamel的m_Age只有一份了,而从Sheep和Camel继承下来的是vbptr。vbptr(virtual base pointer)表示虚基类指针
C++基础(17)——继承相关推荐
- scala面向对象基础---类继承和特质
一.类继承 传送门:Scala基础-类继承 Scala的类继承 调用超类的构造方法 重写超类的成员 3.1.不被继承的成员 3.2.不可重写的成员 3.3.无参方法与字段 子类型多态与动态绑定 抽象类 ...
- 控制导弹发射的计算机应用属于,计算机应用基础17.doc
计算机应用基础17 计算机 17 一.单选题 1.信息实际上是指____. A:基本素材 B:非数值数据 C:数值数据 D:处理后的数据 答案: D 2.在计算机领域,信息是经过转化而成为计算机能够处 ...
- 第二十八节:Java基础-进阶继承,抽象类,接口
前言 Java基础 - 进阶继承,抽象类,接口 进阶继承 class Stu {int age = 1; } class Stuo extends Stu {int agee = 2; } class ...
- 计算机基础17秋在线作业3,东师计算机应用基础17秋在线作业3.doc
计算机应用基础17秋在线作业3 试卷总分:100 测试时间:-- 单选题 多选题 判断题 .单选题(共 25 道试题,共 62.5 分.) 1. 在计算机网络中,表征数据传输可操作性的指标是 A. 误 ...
- Java基础篇--继承(inherit),多态(Polymorphism)
Java基础篇--继承(inherit),多态(Polymorphism) 1. 继承概述 1.1 什么是继承 1.2 为什么要使用继承 1.3 继承的特点 1.4 继承的优点 2. 组合设计模式 2 ...
- Java 基础(继承)
继承 基础 1. 继承的特点 2. super关键字 3. 继承中变量访问特点(就近原则) 4. 继承中成员方法访问特点 5. 继承中构造访问特点 为什么子类中所有构造方法默认都会访问父类无参构造方法 ...
- 东师17计算机应用基础答案,东师计算机应用基础17春在线作业1 免费答案.doc
东师计算机应用基础17春在线作业1 免费答案 一.单选题(共 25 道试题,共 62.5 分.) V 1. "画图"程序在Windows 98的( ) A. "附件&qu ...
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]
类的继承 Java只支持单继承,不允许多重继承 - 一个子类只能有一个父类 - 一个父类可以派生出多个子类 这里写图片描述 子类继承了父类,就继承了父类的方法和属性. 在子类中,可以使用父类中定义的方 ...
- java 知乎面试题_面试题|Java基础17道常见面试题
1. JDK 和 JRE 有什么区别? 面向人群不同: JDK是面向开发人员使用的SDK. JRE是Java Runtime Enviroment是指Java的运行环境,是面向Java程序的使用者. ...
- JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程.]
类的继承 Java只支持单继承,不允许多重继承 - 一个子类只能有一个父类 - 一个父类可以派生出多个子类 子类继承了父类,就继承了父类的方法和属性. 在子类中,可以使用父类中定义的方法和 ...
最新文章
- 图神经网络可以解决现实世界中的问题吗?
- 别把个人信息“玩”丢了
- Material Master
- PHP微信开发框架LaneWeChat框架简介
- 通过ngrok在内网捕获meterpreter反弹
- Linux CentOS下配置SVN+SVN勾子
- linux 设置ftp自启,CentOS vsftpd设置安装自启动配置
- apache+php安装配置
- MySQL基本分区表
- Python中的匿名函数及递归思想简析
- python判断日期为第几天_python怎么判断某一天是一年中的第几天
- [Visual Studio] VS2012调试时很慢的解决方案
- Android中实现Activity的透明背景效果
- 文件上传到QQ邮箱文件中转站,链接
- 卡诺模型(KANO Model)
- 干货| RNA质检的那些事
- Step3:获得单应矩阵(每张图片需要m个棋盘格角点,m≥4)
- 计蒜客--蒜头君的新游戏
- 电磁兼容滤波知识大全
- 怎么在数学表达式里输入小数点
热门文章
- 公务员面试题——人际关系
- Android账号同步系统的建立——AccountManager及其他相关类的运用
- mysql忘记密码找回root密码
- 从零开始前端学习[14]:选择器的优先级
- 2021四川高考成绩等位分查询,2021年四川高考位次排名查询,四川高考位次所对应的学校...
- 小程序项目:微信小程序美容理发店预约系统app——计算机毕业设计
- 除了Micrsoft Office和WPS,有没有免费好用的office软件?
- Qt实现屏幕虚拟软键盘
- 京东新通路,零售价值增量发展的新范式
- 去年190家共享经济平台融资1159亿 共享汽车融资最多