目录

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)——继承相关推荐

  1. scala面向对象基础---类继承和特质

    一.类继承 传送门:Scala基础-类继承 Scala的类继承 调用超类的构造方法 重写超类的成员 3.1.不被继承的成员 3.2.不可重写的成员 3.3.无参方法与字段 子类型多态与动态绑定 抽象类 ...

  2. 控制导弹发射的计算机应用属于,计算机应用基础17.doc

    计算机应用基础17 计算机 17 一.单选题 1.信息实际上是指____. A:基本素材 B:非数值数据 C:数值数据 D:处理后的数据 答案: D 2.在计算机领域,信息是经过转化而成为计算机能够处 ...

  3. 第二十八节:Java基础-进阶继承,抽象类,接口

    前言 Java基础 - 进阶继承,抽象类,接口 进阶继承 class Stu {int age = 1; } class Stuo extends Stu {int agee = 2; } class ...

  4. 计算机基础17秋在线作业3,东师计算机应用基础17秋在线作业3.doc

    计算机应用基础17秋在线作业3 试卷总分:100 测试时间:-- 单选题 多选题 判断题 .单选题(共 25 道试题,共 62.5 分.) 1. 在计算机网络中,表征数据传输可操作性的指标是 A. 误 ...

  5. Java基础篇--继承(inherit),多态(Polymorphism)

    Java基础篇--继承(inherit),多态(Polymorphism) 1. 继承概述 1.1 什么是继承 1.2 为什么要使用继承 1.3 继承的特点 1.4 继承的优点 2. 组合设计模式 2 ...

  6. Java 基础(继承)

    继承 基础 1. 继承的特点 2. super关键字 3. 继承中变量访问特点(就近原则) 4. 继承中成员方法访问特点 5. 继承中构造访问特点 为什么子类中所有构造方法默认都会访问父类无参构造方法 ...

  7. 东师17计算机应用基础答案,东师计算机应用基础17春在线作业1 免费答案.doc

    东师计算机应用基础17春在线作业1 免费答案 一.单选题(共 25 道试题,共 62.5 分.) V 1. "画图"程序在Windows 98的( ) A. "附件&qu ...

  8. JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]

    类的继承 Java只支持单继承,不允许多重继承 - 一个子类只能有一个父类 - 一个父类可以派生出多个子类 这里写图片描述 子类继承了父类,就继承了父类的方法和属性. 在子类中,可以使用父类中定义的方 ...

  9. java 知乎面试题_面试题|Java基础17道常见面试题

    1. JDK 和 JRE 有什么区别? 面向人群不同: JDK是面向开发人员使用的SDK. JRE是Java Runtime Enviroment是指Java的运行环境,是面向Java程序的使用者. ...

  10. JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程.]

    类的继承 Java只支持单继承,不允许多重继承  - 一个子类只能有一个父类  - 一个父类可以派生出多个子类    子类继承了父类,就继承了父类的方法和属性.  在子类中,可以使用父类中定义的方法和 ...

最新文章

  1. 图神经网络可以解决现实世界中的问题吗?
  2. 别把个人信息“玩”丢了
  3. Material Master
  4. PHP微信开发框架LaneWeChat框架简介
  5. 通过ngrok在内网捕获meterpreter反弹
  6. Linux CentOS下配置SVN+SVN勾子
  7. linux 设置ftp自启,CentOS vsftpd设置安装自启动配置
  8. apache+php安装配置
  9. MySQL基本分区表
  10. Python中的匿名函数及递归思想简析
  11. python判断日期为第几天_python怎么判断某一天是一年中的第几天
  12. [Visual Studio] VS2012调试时很慢的解决方案
  13. Android中实现Activity的透明背景效果
  14. 文件上传到QQ邮箱文件中转站,链接
  15. 卡诺模型(KANO Model)
  16. 干货| RNA质检的那些事
  17. Step3:获得单应矩阵(每张图片需要m个棋盘格角点,m≥4)
  18. 计蒜客--蒜头君的新游戏
  19. 电磁兼容滤波知识大全
  20. 怎么在数学表达式里输入小数点

热门文章

  1. 公务员面试题——人际关系
  2. Android账号同步系统的建立——AccountManager及其他相关类的运用
  3. mysql忘记密码找回root密码
  4. 从零开始前端学习[14]:选择器的优先级
  5. 2021四川高考成绩等位分查询,2021年四川高考位次排名查询,四川高考位次所对应的学校...
  6. 小程序项目:微信小程序美容理发店预约系统app——计算机毕业设计
  7. 除了Micrsoft Office和WPS,有没有免费好用的office软件?
  8. Qt实现屏幕虚拟软键盘
  9. 京东新通路,零售价值增量发展的新范式
  10. 去年190家共享经济平台融资1159亿 共享汽车融资最多