C++当中的继承

  在C++当中继承是一个非常重要的语法。我们可以使用继承快速的进行代码的复用以及对代码进行扩展操作。首先我们来进行学习继承的基本语法。

  (一)继承的语法方式

  还记得我们之前学习的访问限定符吗?就是class里面的private,public,protected限定符。我们可以根据限定符的不同设置访问类当中数据的权限。public限制的区域我们可以通过对象在类外面就可以进行访问。protected限制的区域在类当中其实跟private限定的区域没有什么不同,都是可以在类里面进行访问,但是在类外面不能通过创建的对象进行访问。

  对于我们的继承同样需要用到这三个限定符:在继承当中这三种限定符可以表示继承的方式。其中public表示公开继承,protected表示保护继承,private表示私有继承。

  继承的限定符和类当中的限定符是共同作用于我们类当中的成员函数和成员变量的。比如:对于共有继承,对于我们类当中继承的使用权限就是最大的,继承之后我们基类当中的所有的原有元素的权限均保持不变。对于保护继承来说,对于基类当中的公有的成员函数和成员变量会缩小一下权限变为保护的私有变量,其余变量和函数权限保持不变。对于私有继承所展示的权限是最小的我们不能使用基类当中的任何内容,包括在类的内部也不行。

   但是需要我们注意的是:在继承这一部分来说,protected保护继承就会跟我们的private继承有很大程度上的区别。对于我们的保护继承来说我们可以在类的内部进行访问该部分的成员变量或者成员函数,但是我们不允许在类的外面访问该部分的成员函数(实质上就相当于我们之前的private限定之后的区域)。对于private继承来说我们不允许在任何位置进行访问,包括在类的内部也是。

(二)基类和派生类进行转换

  这一部分我们需要理解基类和派生类进行转换的过程,首先我们都知道指定的变量即使类型不同的时候我们的编译器也会进行适当的隐式类型转换操作。如果允许会自动将数据转换成为我们想要的数据。例如:

double d=1.1;
int i=d;   
//系统会自动进行强制类型转换操作,
//将double类型的数据转换成为int类型的数据

  对于我们的基类跟派生类也不例外,同样会自动进行转换,但是在转换的时候有很多隐形的要求。对于我们的派生类来说,在其中会包含我们基类当中的数据,同时可能会有新的数据出现。其结构就类似于下图所示:

  所以在进行转换的时候我们就需要进行注意了:我们只能使用派生类对基类进行赋值,但是不能使用基类对于我们的派生类进行赋值。其实很容易进行理解:在派生类当中我们会有一些新的数据产生,这个时候如果我们使用基类给派生类进行赋值的时候就会缺失这一部分的数据。但是如果我们使用派生类对于我们的基类进行赋值的时候不会缺失任何的数据,只需要进行数据的切片即可。编译器会自动找出跟基类相同的数据进行切片之后直接赋值。

  使用派生类给基类进行赋值:

  程序运行一切正常。

  使用基类给派生类进行赋值:

 系统产生报错,提示我们左操作数不匹配的问题。

 估计大家会想起一个很古老的问题:是不是没有加const的原因呢?我们来回顾一下什么时候在类型转换的时候需要加上const对类型进行修饰:

  当我们在数据转换的时候我们曾经有过一个概念,数据在隐式类型转换的时候我们会产生一个临时的中间变量,这个临时的中间变量具有常量的属性。所以如果我们想要进行引用的时候需要使用const修饰符进行修饰。不然就会产生报错。

  我们会发现我们使用const修饰之后报错消失了。那么我们回过头查看继承这部分出现的问题:

  我们会发现这一部分的报错并不涉及任何引用方面的内容,所以可以断定不是相同的错误原因。

  那么我们在使用派生类对基类进行赋值的时候,如果使用引用是否需要加上const才可以编译通过呢?

  我们通过实践验证的时候就会发现:我们其实并不需要使用const进行任何的修饰操作就可以正常的运行代码,这是因为我们的切片之后的操作只是一个单纯的复制操作,并不存在类型转换的问题,所以不需要产生临时的中间变量,也就不存在需要使用const修饰的问题。

  (三)继承当中的作用域

  对于基类当中的变量来说其作用域就是在基类当中,但是一旦被继承之后根据继承的方式不同我们同样可以在不同的地方进行不同的访问和修改。如果当我们使用引用或者指针指向派生类当中的基类的时候就会将我们的基类跟我们的派生类链接起来,形成一个统一的整体,在我们修改派生类当中的基类成员的时候同样会修改到我们基类当中原本存储的数据。例如:

  同样的道理我们修改a的时候也会修改到我们的派生类当中的基类当中的元素。其实很好理解,因为我们使用引用的时候仅仅是将数据切片出来之后,使用一个基类引用而已,数据还是我们派生类当中保存的数据。

  那么我们会很容易想到:要是在基类当中存在跟我们派生类当中的元素重复的成员类型呢?比如说同名的成员函数以及成员变量之类的。

  在语法当中我们将继承当中的同名的成员函数和成员变量叫做隐藏。对于构成隐藏的函数或者变量来说我们只能在特定的区域内访问特定的对象。例如:

  运行相应的程序之后我们会发现我们调用的是派生类当中的成员函数,并不是我们基类当中的成员函数,这个很好理解,编译器在调用函数的时候会自动进行就近检查。如果定义的类当中存在该函数的时候就不会到基类当中进行查找了,如果没有的话就会进入基类当中进行相应的查找操作。那么问题来了:我们要怎样才可以调用基类当中被隐藏的成员函数呢?这个时候我们就需要使用域作用访问限定符进行访问了。这样我们的编译器就会直接进入我们指定的类当中进行查找。测试如下:

  (四)派生类当中的默认成员函数

  记得我们在学习类的时候有一部分会学到默认成员函数的概念,默认的成员函数大致分为以下几种:第一种为默认构造函数,也就是在不手动添加构造函数的时候默认生成的构造函数,还有拷贝构造函数,当我们不手动编写的时候系统同样会默认生成一个拷贝构造。赋值运算符重载,以及析构函数,这几种函数当我们不主动设置的时候都会自动进行生成。

  那么对于我们的派生类默认成员函数有什么要求呢?对于我们的派生类来说其中实质上是由两部分组成的,第一类是我们通过继承得到的基类的部分,另一部分是我们派生类自己专属的那一部分。当我们在调用派生类对象的时候,系统为了保证我们派生类当中基类部分的数据完整性会自动调用基类当中的构造函数,对基类当中的数据进行初始化操作。之后我们在通过我们派生类的构造函数对我们的派生类再进行初始化,最终得到我们的结果。例如:

  当我们在创建B对象的时候系统会自动调用A的构造函数对A进行初始化操作,如果我们没有指定调用A的构造函数的话,系统就会自动调用默认的构造函数。但是需要我们注意的是:是否真的存在默认的构造函数。所谓的默认的构造函数实质上也就是系统自动生成的构造函数,但是我们不能自己编写构造函数,否则系统默认生成的构造函数就会失效。还有就是我们自己编写的无参的构造函数,最后就是全缺省的构造函数。

  当我们不存在默认的构造函数,同时没有进行指定调用特定的构造函数的时候系统就会产生报错:

  实质上并不是一定要拥有无参的构造函数,我们也可以指定调用已经存在的构造函数。

  当我们明确指出我们需要调用的构造函数的时候即使没有默认的构造函数程序也可以正常的运行。对于我们的其他的默认成员函数也是相同的。

  但是我们需要注意的是构造函数调用的顺序,首先我们的编译器会自动调用基类对象的构造函数,之后才会调用我们派生类的构造函数进行初始化,这是因为我们在派生类的构造函数当中可能会对基类当中的成员变量以及成员函数进行调用,先调用基类的构造函数就可以避免未知错误的产生。

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿白逆袭记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值