C++中的继承和多继承
一、学习笔记
1.继承
- class Student : public Person {
- ...
- }
2.继承时权限
派生类中可以直接访问父类的protected成员,但是不能访问其private成员,若继承时不写public,默认就是private继承。
- 继承方式\基类中的访问属性 public protected private
- public public protected 隔离
- protected protected protected 隔离
- private private private 隔离
(1) 无论哪种继承方式,在派生类的内部使用父类时并无差别
(2) 不同的继承方式,会影响这两方面:外部代码对派生类的使用,派生类的子类对派生类成员的使用。
3.using更改继承成员的权限
①修改成员变量的
在派生类中的public:下使用using Father::room_key;可以将父类的protected成员room_key提升为public权限,此时可以直接在main()中访问!
在派生类中的private:下使用using Father::room_key;可以将父类的protected成员room_key降低为private权限,此时就不可以在类外进行访问!
若在派生类中可以使用using关键字将父类的public成员降为private权限,这样子类的子类就继承不到这个属性了。
①修改成员函数的
在派生类中的public:下使用using Father::getRoomKey;可以将父类的protected成员getRoomKey()成员函数提升为public权限。可以直接使用函数名而不是
函数签名的原因是这里仅仅是修改权限,父类重载的所有getRoomKey()都变为public了,之后类外调用根据参数匹配规则不变。
也就是说可以使用using关键字调整继承来的成员的访问权限,但前提是这些成员对你这个类可见。
4.构造函数子类也会继承父类的,但是其构造的是从父类那里继承过来的部分。
5.子类中若是实现了与父类的同名函数getName(),可以Parent::getName()来调用父类的getName(), 但是操作的成员变量是子类继承父类的部分。
6.子类定义与继承来的可见的成员变量同名的成员变量也是可以的。重新定义函数签名和函数名都相同的函数叫做复写。
7.继承的父类的成员函数中操作的成员变量都是子类继承于父类的。父类的成员函数操作的成员变量都是父类的,除非子类进行了复写。
8.在子类的外部可以通过s1.Father::getRoomKey();调用父类的函数,在子类的内部可以通过Father::getRoomKey();调用父类的函数。
9.多重继承
- class Sofabed: public Sofa, public Bed {
- ...
- }
- Sofabed s;
- s::Sofa::setWeight() //指明调用Sofa的setWeight()
10.多继承会导致二义性,解决办法是使用虚继承。
解决:把共性的东西提炼出来,只保留一份备份,放在共有的父类Fourniture中,然后Sofa和Bed都虚继承Fourniture。
- class Sofa : virtual public Fourniture
- class Bed : virtual public Fourniture
- class Sofabed: public Sofa, public Bed
11.虚继承内存分布
虚继承的成员在Sofabed类中只会保留一份备份,也就是说Fourniture类中定义的成员只会在SofaBed类中只保留一份。
12.要尽量避免使用多继承,它会使程序变得更加复杂,更容易出错。
13.带有继承和虚继承的构造函数的调用次序
先父后子:
(1)先调用基类的构造函数
①先调用虚拟基类的构造函数,再调用一般基类的构造函数。注意是先把所有虚基类的构造函数执行完后再执行的一般基类的构造函数。
(2)然后再调用自身的构造函数
①先调用对象成员的构造函数,然后再调用自己的构造函数。
对于虚继承的基类,基类的构造函数只执行一次。
eg: 如下两次继承,Furniture和Verication3C,它两个的构造函数是被调用一次!
class Soft : virtual public Furniture, virtual public Verication3C
class Bed : virtual public Furniture, virtual public Verication3C
14.子类的构造函数给父类的构造函数传参数
- class LeftRightSofabed : public Sofabed, virtual public LeftRightCom {
- private:
- Date date;
- public:
- LeftRightSofabed(char *str1) : Sofabed(str1), LeftRightCom(str1), date(str1) { //注意这里的data用的是成员名,而不是类名
- cout <<"LeftRightSofabed()"<<endl;
- }
- };
试验发现,在子类中使用初始化列表初始化虚继承的类无法触发虚继承的类中的有参构造函数被调用,调用的还是无参构造函数。
eg:上面代码中LeftRightCom()的有参构造函数不会被调用,调用的还是无参构造函数。
二、例子
1.单继承例子
- #include <iostream>
- using namespace std;
- class Father {
- private:
- int money;
- char *name;
- protected:
- int room_key;
- int getRoomKey(int) {
- cout << "getRoomKey(int) name=" << name << endl;
- return room_key;
- }
- public:
- int getRoomKey(void) {
- cout << "getRoomKey(void) name=" << name << endl;
- return room_key;
- }
- Father() {
- money = ;
- room_key = ;
- name = "father_begin";
- cout << "Father()" << endl;
- }
- Father(char *name) {
- this->name = name;
- cout << "Father(char *name)" << "name= " << this->name << endl;
- }
- ~Father() {
- cout << "~Father()" << endl;
- }
- int getMoney(void) {
- cout << "int getMoney(void)" << endl;
- return money;
- }
- void setMoney(int money) {
- cout << "void setMoney(int money)" << endl;
- this->money = money;
- }
- };
- class Son : public Father {
- char *name;
- public:
- using Father::room_key;
- using Father::getRoomKey;
- Son(char *name){
- this->name = name;
- cout << "Son()" << "name= " << this->name << endl;
- }
- ~Son() {
- cout << "~Son()" << "name= " << this->name << endl;
- }
- int getRoomKey(void) {
- Father::getRoomKey();
- cout << "getRoomKey(void) name=" << name << endl;
- return room_key;
- }
- };
- int main()
- {
- Son s1("son_name");
- s1.getRoomKey();
- s1.getRoomKey();
- s1.Father::getRoomKey();
- s1.getMoney();
- cout <<"s1.room_key= "<< s1.room_key << endl;
- return ;
- }
- /*
- Father()
- Son()name= son_name
- getRoomKey(void) name=father_begin
- getRoomKey(void) name=son_name
- getRoomKey(int) name=father_begin
- getRoomKey(void) name=father_begin
- int getMoney(void)
- s1.room_key= 1
- ~Son()name= son_name
- ~Father()
- */
2.多继承中使用虚继承来处理成员变量二义性问题
- #include <iostream>
- using namespace std;
- class Furniture {
- int weight;
- public:
- int size;
- int getWeight() {
- cout << "Furniture::getWeight()" << endl;
- return weight;
- }
- };
- class Sofa : virtual public Furniture {
- int sofa;
- public:
- void getSofa() {
- cout << "Sofa::getSofa()" << endl;
- }
- };
- class Bed : virtual public Furniture {
- int bed;
- public:
- void getBed() {
- cout << "Bed::getBed()" << endl;
- }
- };
- class Sofabed : public Sofa, public Bed {
- int color;
- public:
- int getColor() {
- cout << "Sofabed::getColor()" << endl;
- return color;
- }
- int getSize() {
- cout << "Sofabed::getSize()" << endl;
- return size;
- }
- };
- int main() {
- Sofa so;
- Bed be;
- Sofabed sb;
- so.getWeight();
- so.getSofa();
- be.getWeight();
- be.getBed();
- sb.getSize();
- sb.getSofa();
- sb.getBed();
- sb.getWeight();
- return ;
- }
- /*
- Furniture::getWeight()
- Sofa::getSofa()
- Furniture::getWeight()
- Bed::getBed()
- Sofabed::getSize()
- Sofa::getSofa()
- Bed::getBed()
- Furniture::getWeight()
- */
3.虚继承构造函数中调用父类构造函数的例子
- #include <iostream>
- using namespace std;
- class Furniture {
- public:
- Furniture() {
- cout << "Furniture()" << endl;
- }
- Furniture(char *abc) {
- cout << "Furniture(abc)" << endl;
- }
- };
- class Verication3C {
- public:
- Verication3C() {
- cout << "Verication3C()" << endl;
- }
- Verication3C(char *abc) {
- cout << "Verication3C(abc)" << endl;
- }
- };
- class Soft : virtual public Furniture, virtual public Verication3C {
- public:
- Soft() {
- cout << "Soft()" << endl;
- }
- Soft(char *abc) : Furniture(abc), Verication3C(abc) {
- cout << "Soft(abc)" << endl;
- }
- };
- class Bed : virtual public Furniture, virtual public Verication3C {
- public:
- Bed() {
- cout << "Bed()" << endl;
- }
- Bed(char *abc) : Furniture(abc), Verication3C(abc){
- cout << "Bed(abc)" << endl;
- }
- };
- class SoftBed : public Soft, public Bed {
- public:
- SoftBed() {
- cout << "SoftBed()" << endl;
- }
- SoftBed(char *abc) : Soft(abc), Bed(abc){
- cout << "SoftBed(abc)" << endl;
- }
- };
- class LeightWrightCom {
- public:
- LeightWrightCom() {
- cout << "LeightWrightCom()" << endl;
- }
- LeightWrightCom(char *abc) {
- cout << "LeightWrightCom(abc)" << endl;
- }
- };
- class Type {
- public:
- Type() {
- cout << "Type()" << endl;
- }
- Type(char *abc) {
- cout << "Type(abc)" << endl;
- }
- };
- class Date {
- public:
- Date() {
- cout << "Date()" << endl;
- }
- Date(char *abc) {
- cout << "Date(abc)" << endl;
- }
- };
- class LeightWrightSofaBed : public SoftBed, virtual public LeightWrightCom {
- Type type;
- Date date;
- public:
- LeightWrightSofaBed() {
- cout << "LeightWrightSofaBed()" << endl;
- }
- LeightWrightSofaBed(char *abc) : SoftBed(abc), LeightWrightCom(abc), type(abc), date(abc) {
- cout << "LeightWrightSofaBed(abc)" << endl;
- }
- };
- int main()
- {
- LeightWrightSofaBed l1("lll");
- return ;
- }
- /*
- Furniture() //没有调用有参构造函数!!
- Verication3C() //没有调用有参构造函数!!
- LeightWrightCom(abc) //调用了有参构造函数
- Soft(abc)
- Bed(abc)
- SoftBed(abc)
- Type(abc)
- Date(abc)
- LeightWrightSofaBed(abc)
- */
C++中的继承和多继承的更多相关文章
- C++中的多重继承与虚继承的问题
1.C++支持多重继承,但是一般情况下,建议使用单一继承. 类D继承自B类和C类,而B类和C类都继承自类A,因此出现下图所示情况: A A \ / B C ...
- HIbernate学习笔记(七) hibernate中的集合映射和继承映射
九. 集合映射 1. Set 2. List a) @OrderBy 注意:List与Set注解是一样的,就是把Set更改为List就可以了 private List< ...
- JS中通过call方法实现继承
原文:JS中通过call方法实现继承 讲解都写在注释里面了,有不对的地方请拍砖,谢谢! <html xmlns="http://www.w3.org/1999/xhtml"& ...
- Java中的集合类型的继承关系图
Java中的集合类型的继承关系图
- 盘点CSS中可以和不可以继承的属性
CSS中可以和不可以继承的属性 一.无继承性的属性 1.display:规定元素应该生成的框的类型 2.文本属性: vertical-align:垂直文本对齐 text-decoration:规定 ...
- 对Java中多态,封装,继承的认识(重要)
一.Java面向对象编程有三大特性:封装,继承,多态 在了解多态之前我觉得应该先了解一下 ...
- oc中protocol、category和继承的区别
OC中protocol.category和继承的区别以前还是有点迷糊,面试的时候说的有点混乱,现在结合一些资料总结一下. 利用继承,多态是一个很好的保持"对扩展开放.对更改封闭"( ...
- C++ 中私有继承、保护继承与公有继承
区别 下面通过一个示例来介绍三种继承的区别. 定义一个基类(假设为一个快退休的富豪): class RichMan { public: RichMan(); ~RichMan(); int m_com ...
- js中的对象创建与继承
对象创建 1.工厂模式 优点:解决了创建多个相似对象的问题 缺点:没有解决对象识别问题:每一个对象都有一套自己的函数,浪费资源 function createPerson(name, age, job ...
- Es5中的类和静态方法 继承
Es5中的类和静态方法 继承(原型链继承.对象冒充继承.原型链+对象冒充组合继承) // es5里面的类 //1.最简单的类 // function Person(){ // this.name='张 ...
随机推荐
- MATLAB图片折腾3
把视频抽帧,转化成图片 我的代码如下,成功实现clc;clear;videofilename='k:\GraduationWork\Resource\video.wmv'; %where you pu ...
- 深入理解java虚拟机---虚拟机工具jinfo(十五)
作用: 实时查看和调整虚拟机参数. jinfo 是jdk自带的一个工具,它可以用来查看正在运行的java应用程序的扩展参数(JVM中-X标示的参数):甚至支持在运行时修改部分参数. 1.通过以下的命令 ...
- Install SharePoint 2013 with SP1 on Windows Server 2012 R2 error - This Product requires .NF 4.5
博客地址:http://blog.csdn.net/FoxDave 最近因为项目需要要搭建SharePoint 2013的开发环境. 准备了Windows Server 2012 R2系统和Sha ...
- Aizu - 2681(括号匹配)
Problem Statement You are given nn strings str1,str2,…,strnstr1,str2,…,strn, each consisting of ( an ...
- <YARN><MRv2><Spark on YARN>
MRv1 VS MRv2 MRv1: - JobTracker: 资源管理 & 作业控制- 每个作业由一个JobInProgress控制,每个任务由一个TaskInProgress控制.由于每 ...
- 『翻译』Android USB Host
USB Host When your Android-powered device is in USB host mode, it acts as the USB host, powers the b ...
- python 异常处理函数--raise
Python 异常处理--raise函数用法 在Python中,要想引发异常,最简单的形式就是输入关键字raise,后跟要引发的异常的名称.异常名称标识出具体的类: Python异常处理是那些类的对象 ...
- 在Linux系统下mail命令的用法
在Linux系统下mail命令的测试 1. 最简单的一个例子: mail -s test admin@aispider.com 这条命令的结果是发一封标题为test的空信给后面的邮箱,如果你有mta并 ...
- java学习笔记17(Calendarl类)
Calendar类:(日历) 用法:Calendar是一个抽象类:不能实例化(不能new),使用时通过子类完成实现,不过这个类不需要创建子类对象,而是通过静态方法直接获取: 获取对象方法:getIns ...
- HTTPS双向认证+USB硬件加密锁(加密狗)配置
环境: Ubuntu14.04,apache2.4.7, openssl1.0.1f 安装apache2 apt-get install apache2 -y 一般openssl默认已经安装 开启a ...