C++学习笔记(十二)------is_a关系(继承关系)

 

你好,这里是争做图书馆扫地僧的小白。

个人主页:争做图书馆扫地僧的小白_-CSDN博客

目标:希望通过学习技术,期待着改变世界。


 提示:以下是本篇文章正文内容,下面案例可供参考

文章目录

前言  

一、继承关系的语法形式

        (一)单继承的语法格式:

        (二)多继承的语法形式

         (三)单继承关系举例

二、继承关系的意义

三、继承关系的权限问题

四、单继承

        (一)单继承关系下的内存布局        

        1.举个例子,代码如下:

        2.图解如下:

(二)自动隐藏机制

(三)继承关系下的类型兼容规则

 五、多继承

        (一)多继承举例说明:

(二)多继承的内存布局

总结


前言  

        随着技术的革新,出现各种各样的编程语言,C++就是其中之一,作为最受欢迎的编程语言之一,C++带给开发者们最大的惊喜便是其强大的特性。一方面跟C兼容,可以直面系统底层API,SDK,另一方面提供了很多范式,足够的抽象能力,面向对象,操作符重载,模板等。

        之前的C++学习笔记(十一)------has_a和use_a关系-CSDN博客已经讲解了has_a和use_a关系,本篇将讲解最为重要的一种关系即is_a关系(继承关系)。


一、继承关系的语法形式

        (一)单继承的语法格式:

class 子类 : 继承权限 + 父类
{//继承即是子类继承了父类中的所有属性与方法(构造函数除外)
};

        (二)多继承的语法形式

class 子类 : 继承权限1,父类1,继承权限2,父类2,... 继承权限n,父类n
{//子类继承多个父类中的所有属性与方法。
}

        注意:继承关系中,子类并不继承父类中的构造函数。因为构造函数是特别的为本类域进行初始化的函数,并不会被继承。子类中要有子类的默认构造或自定义有参构造。

       多继承一般情况不使用,如果使用多用于集成多个抽象类,原因见下文的多继承部分。

         (三)单继承关系举例

#include <iostream>
using namespace std;
class Car
{
public:int price;
public:void run(){cout << "汽车在行驶" << endl;}
};
class BYD : public Car
{
public:void uniqueEmblem(){cout << "有着中国特色的车标" << endl;}
};
int main()
{BYD byd;byd.run();byd.price;byd.uniqueEmblem();return 0;
}

二、继承关系的意义

        继承关系的意义是:代码复用性与高拓展性。

        使用继承关系的步骤:首先把这类的事件抽象出来一些共有的属性与特征,把它们定义为父类。再用这个父类,对具有不同特点的子类进行派生,就可以派生出各种不同的子类。这样的子类有着公有的属性,还有着各自独特的性质。

三、继承关系的权限问题

#include <iostream>
using namespace std;class Car
{
public:int price;
public:void run(){cout << "汽车在行驶" << endl;}
};class BYD : private Car
{
public:void uniqueEmblem(){cout << "有着中国特色的车标" << endl;}
};int main()
{BYD byd;byd.run();byd.price;byd.uniqueEmblem();return 0;
}

         继承关系图如下所示,如图所示当子类继承父类时,可以理解为将父类整体打包,将其作为一整个属性赋给子类。

        注意:每一种继承关系对父类各种权限的属性的访问也是有区别的。当public继承时,对父类中private权限的属性不管是在子类的类外还是类内都没有访问权限;对父类中protected权限的属性在子类的类内有访问权限且为protected访问权限,在子类类外没有访问权限;对父类中public属性的属性不管是在子类类内还是类外都是public访问权限。其余两种不在采用文字形式进行描述,详细的直观的描述见下面的表格。

四、单继承

        (一)单继承关系下的内存布局        

        子类对象被构造时,先构造父类,然后再调用子类的构造完成对子类类域中拓展的属性进行初始化,此时,子类的对象具有具体初始值。析构的时候先析构子类,然后在析构父类。

        注意的是子类析构被执行,父类析构也一定被析构。原因是内存绑定

        1.举个例子,代码如下:

#include <iostream>
using namespace std;
class Car
{
private:int price;
public:void run(){cout << "汽车在行驶" << endl;}Car(){cout << "Car父类的构造" << endl;}~Car(){cout << "Car父类的析构" << endl;}
};
class BYD : private Car
{
public:BYD(){cout << "BYD子类的构造"  << endl;}~BYD(){cout << "BYD子类的析构" << endl;}
};int main()
{BYD byd;return 0;
}

        2.图解如下:

(二)自动隐藏机制

        当子类中有与父类同名属性或函数时,父类中的同名属性或行为将自动隐藏在自己的父类的类域之中,如果想访问父类类域之中的属性或行为,就使用域名::访问。

        举个例子,代码如下:

#include <iostream>
#include <unistd.h>
using namespace std;
class Car
{
public:int price = 10000;
public:void run(){cout << "车子正在行驶之中" << endl;}Car(){cout << "Car父类的构造" << endl;}~Car(){cout << "Car父类的析构" << endl;}
};class BYD : public Car
{
public:int weight = 20000;
public:void run(){cout << "BYD高速行驶" << endl;}BYD(){cout << "BYD子类的构造" << endl;}~BYD(){cout << "BYD子类的析构" << endl;}
};
int main()
{BYD byd;cout << byd.Car::price << endl;byd.run();byd.Car::run();return 0;
}

(三)继承关系下的类型兼容规则

        在之前我们学到当使用指针的时候,要保证等号前后的指针类型要相同才可以,在继承中不然。继承关系中父类指针或者引用可以安全的指向或者引用子类类型的对象,但是子类指针或者引用并不能指向或者引用父类类型的对象。

        需要注意的是使用父类指针在释放资源时,注意要强转成子类指针才可以完全释放,不然会造成资源的泄露。

        还需要注意的是当父类中只有有参构造的时候,子类的构造函数处应该进行初始化列表的操作,指定父类的有参构造对其进行初始化操作,否则会报错。

        举个例子,代码如下:

#include <iostream>
#include <unistd.h>
using namespace std;
class Car
{
public:int price = 10000;
public:void run(){cout << "汽车在行驶" << endl;}Car(int price){cout << "Car父类的构造" << endl;}~Car(){cout << "Car父类的析构" << endl;}
};
class BYD : public Car
{
public:int price = 20000;
public:void run(){cout << "BYD高速行驶" << endl;}BYD():Car(1)  {cout << "BYD子类的构造" << endl;}~BYD(){cout << "BYD子类的析构" << endl;}
};
int main()
{//栈上定义对象BYD byd;Car* c = &byd;   //父类属性的指针可以安全的指向子类属性c->run();        //调用父类中子类和父类公有的run方法cout << c->price << endl;  //10000Car& ref_c = byd;  //父类属性的引用可以安全的指向子类属性ref_c.run();        //调用父类中子类和父类公有的run方法cout << ref_c.price << endl;  //10000//用堆上的对象:Car* ptr_c = new BYD();ptr_c->run();delete (BYD*)ptr_c;  //释放指针时,需要进行强转,否则只采用delete ptr_c,只会析构父类,而子类指向的堆上资源并没有被回收return 0;
}

 五、多继承

        在多继承时,虽然多继承可以大在提高代码的复用性,但是会造成代码冗余,当多个父类中有同名函数或属性时,在访问时候会出现二义性的问题。

        需要注意使用类域::访问的方式进行指定访问,但是这样给程序设计带来很多不便,所以多继承在开发时尽量避免。如果一定要使用多继承时,推荐使用多继承多个抽象类,因为抽象类一般都没有具体的属性,只有纯虚函数。

        (一)多继承举例说明:

#include <iostream>
using namespace std;
class Phone
{
public:int power;
public:void sendMessage(){cout << "发消息" << endl;}
};
class Pad
{
public:int power;
public:void playGame(){cout << "玩游戏" << endl;}
};
class Computer : public Phone, public Pad
{};
int main()
{Computer computer;computer.sendMessage();computer.playGame();cout << computer.Phone::power << endl;  cout << sizeof(Computer) << endl;return 0;
}

(二)多继承的内存布局

        注意:当上述例子中定义Phone *p = &computer 和 Pad *p1 = &computer 这两个指针指向的地址空间是否一致?

        答案是不一致的,当使用父类指针指向子类时,在继承中父类指针永远指向的是自己类中的起始地址。

        当然多继承也符合继承关系下的类型兼容规则。


总结

        以上就是今天要讲的内容,本文将is_a关系(继承关系)进行了详细的介绍,分成了单继承和多继承,并对继承中权限问题和内存布局进行了详细的介绍,当然多继承中还存在着一种特殊的构造形式即为菱形继承,这部分将留作下篇笔记进行撰写。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/284480.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HIVE窗口函数

什么是窗口函数 hive中开窗函数通过over关键字声明&#xff1b;窗口函数&#xff0c;准确地说&#xff0c;函数在窗口中的应用&#xff1b;比如sum函数不仅可在group by后聚合&#xff0c;在可在窗口中应用&#xff1b; hive中groupby算子和开窗over&#xff0c;shuffle的逻辑…

使用DTS将自建MySQL迁移至PolarDB MySQL引擎,探索DTS全量数据校验

1. 领取免费的ECS和PolarDB资源 一旦您注册了阿里云账号并填写了您的账号和支付信息&#xff0c;您就可以申请免费试用我们的产品&#xff08;如ECS、PolarDB、RDS等服务&#xff09;。 1.1. 申请 ECS 免费试用 1. 在 阿里云免费试用中心&#xff0c;找到ECS&#xff0c;单击…

【数据结构】八大排序之简单选择排序算法

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 一.简单选择排序简介及思路 二.简单选择排序的代码实现 三.简单选择排序的优化 四.简单选择排序的时间复杂度分析 结语 一.简单选择排序简介及思路 简单选择排序算法…

力扣225. 用队列实现栈【附进阶版】

文章目录 力扣225. 用队列实现栈示例思路及其实现两个队列模拟栈一个队列模拟栈 力扣225. 用队列实现栈 示例 思路及其实现 两个队列模拟栈 队列是先进先出的规则&#xff0c;把一个队列中的数据导入另一个队列中&#xff0c;数据的顺序并没有变&#xff0c;并没有变成先进后…

羊大师之冷天喝羊的好处大揭秘!

最近&#xff0c;冷天喝羊已经成为了一种趋势&#xff0c;受到了越来越多人的关注与喜爱。你可能会好奇&#xff0c;为什么冷天喝羊有那么多的好处呢&#xff1f;今天小编羊大师将带大家一起探索这个问题&#xff0c;揭秘冷天喝羊带来的种种益处。 冷天喝羊对于保持身体温暖是…

pr-卡点

目录 自定义创建序列关闭拉动时音频 自定义创建序列 关闭拉动时音频 难点&#xff1a;寻找精准衔接画面

Transformer Decoder的输入

大部分引用参考了既安的https://www.zhihu.com/question/337886108/answer/893002189这篇文章&#xff0c;个人认为写的很清晰&#xff0c;此外补充了一些自己的笔记。 弄清楚Decoder的输入输出&#xff0c;关键在于图示三个箭头的位置&#xff1a; 以翻译为例&#xff1a; 输…

算法分析与设计课后练习25

问题描述 用LC分枝限界算法求解下面的0-1背包问题&#xff0c;并画出 所生成的状态空间树。 ① N 5, M12, (p1, p2, …, p5) (10, 15, 6, 8, 4), (w1, w2, …, w5) (4, 6, 3, 4, 2) 。 用FIFO分枝限界算法求解下面的0-1背包问题&#xff0c;并画 出所生成的状态空间树。 ②…

Peter算法小课堂—简单建模(4)

太戈编程1655题 一条直线上&#xff0c;你安排了n个哨兵站岗放哨&#xff0c;编号从1到n。其中i号哨兵的坐标位置是x[i]。不会有哨兵站在相同的位置。作为指挥官&#xff0c;你需要知道3个信息&#xff1a; 1.从左到右&#xff0c;每个哨兵的坐标依次是几? 2.从左到右&…

[ 8 种有效方法] 如何在没有备份的情况下恢复 Android 上永久删除的照片?

我们生命中最重要的时刻&#xff0c;但这样做有缺点&#xff0c;其中之一就是数据丢失的风险。您可能倾向于定期删除无意义的照片&#xff0c;同时保存可爱的照片&#xff0c;从而使您的 Android 设备井井有条。然而&#xff0c;有些人在删除自己珍视的图像时不小心犯了错误。您…

VMware----基于 VMware 玩转 CentOS 虚拟机创建、克隆以及配置后台运行

查看原文 文章目录 一、安装 Vmware二、创建 CentOS7 系统的虚拟机三、克隆虚拟机四、设置虚拟机后台运行 一、安装 Vmware &#xff08;1&#xff09;打开VMware下载地址页面&#xff0c;滑动页面&#xff0c;找到如下界面&#xff0c;点击【下载】 &#xff08;2&#xff…

NPM的介绍和使用

初识npm npm是Node.js世界里最流行的包管理器,用于Node模块的发布、安装和管理。npm是Node Package Manager(Node包管理器)的缩写。 利用npm可以非常方便地安装各种第三方包,不需要关心包之间的各种依赖关系,因为npm会自动处理这些繁琐的工作。这极大地简化了项目的配置,使我们…