C++继承重要知识点总结(上)

news2024/11/19 16:49:30

目录

一.前言

二.继承机制

三.父子类赋值兼容规则

四.继承中的作用域

五.子类的默认成员函数

1.构造函数

2.拷贝构造函数

3.赋值重载函数

4.析构函数


一.前言

继承作为C++的三大特性之一,其重要性不言而喻,只有学好了继承才能为后面的多态打下基础。本文会列出继承的一些重要知识点,带你快速掌握要点。

二.继承机制

这里就不画那个3*3的列表了,直接说怎么理解记忆:

  1. 父类的所有成员都会被子类继承下来,但是能不能用就不一定了
  2. 父类的private成员子类不可见
  3. 父类的其它成员在子类中的访问限定符 = 成员在父类的访问限定符和继承方式中权限小的那一个(public < protected < private)
  4. 继承方式不写,默认就是私有继承(struct 默认是公有继承)
     

注:

1.不建议使用private/protected继承,因为继承过来的成员只能在类里面访问

2.私有成员和保护成员的区别是什么?
protected这个访问限定符是专门为继承设计的,父类protected成员在子类中是可以访问的,而private成员虽然子类继承下来了,但是不可见

三.父子类赋值兼容规则

不同类型赋值时,如果是相近类型,可以隐式类型转换,会产生临时对象,但是C++父子类赋值时比较特殊:

在公有继承的基础上(注意必须是公有继承),父类和子类是 "is a" 的关系,子类对象可以赋值给父类对象或父类的引用,父类指针可以指向子类对象。
并且中间不会产生临时对象,这个叫做父子类赋值兼容规则,也叫"切片"
1.如果是对象赋值,则会将子类对象中父类的那部分成员拷贝过去(内置类型值拷贝,自定义类型调用拷贝构造)

2.如果是引用或指针,则引用或指向子类对象中父类的那部分成员

Student s;
Person p =s;   //对象赋值
Person& rp = s;//引用
Person* pp = &s;//指针

四.继承中的作用域

  1. 从父类继承下来的成员和自己定义的成员在不同作用域中,因此父类和子类可以有重名成员
  2. 当使用这个重名的标识符时,访问的是子类的成员,这种现象叫做子类同名成员隐藏了父类同名成员
  3. 如果想要访问父类成员,可以用使用指定作用域的方式

 看一个题目:

class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};
class B : public A
{
public:
	void fun(int i)
	{
		A::fun();
		cout << "func(int i)->" << i << endl;
	}
};
void Test()
{
	B b;
	//b.fun(10);  //默认是访问子类的成员
	//b.A::fun();  //指定作用域访问父类的成员
};

//以上两个fun函数构成隐藏,不是重载!!!因为两个函数不在同一个作用域

 B继承了A的fun,同时实现了自己的fun,请问两个fun构成什么关系?

答:以上两个fun函数构成隐藏,不是重载!!!因为两个函数不在同一个作用域。成员函数满足函数名相同就构成隐藏。

五.子类的默认成员函数

一个擂有六个默认成员函数,但重要的就以下四个:

1.构造函数

  1. 编译器自动生成的默认构造函数会先调用父类的构造函数以初始化父类的成员,然后再初始化自己的成员
  2. 如果自己实现构造函数,父类的成员不能单独初始化,只能使用父类的构造函数整体初始化
  3. 当然,如果你没有调用父类构造函数,编译器也会隐式的调用父类的默认构造函数,自己的自定义类型成员也是同理
Student(int stuid = 111)
		:Person()
		,_stuid(stuid)//自己的内置类型成员
	{}

 

2.拷贝构造函数

  1. 编译器自动生成的拷贝构造函数会先调用父类的拷贝构造函数,然后初始化自己的成员(内置类型值拷贝,自定义类型调用拷贝构造)
  2. 如果自己实现拷贝构造函数,如何显式调用父类的拷贝构造,怎么传参?哪来的父类对象?——直接传子类对象,因为子类对象可以赋给父类引用(切片)
  3. 当然,如果你没有调用父类拷贝构造函数,编译器也会隐式调用父类拷贝构造函数,自己的自定义类型成员也是同理.但如果你没有处理自己的内置类型成员,编译器是不会帮你值拷贝的
Student(const Student& s)
		:Person(s)
		,_stuid(s._stuid)
	{}

 

下面谈一下我对构造函数(普通构造和拷贝构造)的理解,这些可能会对你有所帮助:

1)以上的所有动作都是在初始化列表完成的

2)一个类的的成员变量可以分为三类:从父类继承下来的,自己的自定义类型,自己的内置类型。在初始化列表,编译器有一些隐藏的动作:调用父类构造和自定义类型的构造、可能初始化内置类型(当你声明内置类型时给了一个缺省值的情况下就会帮你初始化,因为这个缺省值实际上给了初始化列表)。
3)当你自己做了这些事,编译器就不再帮你做了

4)注意一下默认拷贝构造和自己实现的拷贝构造的差异,对于内置类型,默认拷贝构造会完成值拷贝,而自己实现的编译器就不再管了,交给你自己去把握。

3.赋值重载函数

  1. 编译器自动生成的赋值重载函数会先调用父类的赋值重载函数,然后处理自己的成员(内置类型值拷贝,自定义类型调用赋值重载)
  2. 如果自己实现赋值重载函数,调用父类的赋值重载函数会出现问题,为什么?因为自己的赋值重载函数把父类的赋值重载函数隐藏了,编译器认为你调用的是自己的赋值重载,所以形成了死递归
  3. 所以需要指定类域才能调用父类的赋值重载函数
Student& operator=(const Student& s)
	{
		Person::operator=(s);
		_stuid = s._stuid;
		return *this;
	}

4.析构函数

先不谈默认析构函数做了哪些工作,我们自己实现一个,先掉掉坑再说:

~Student()
	{
		~Person();
		cout << "Student析构" << endl;
	}

想法:因为父类是先创建的,所以先把父类析构了,然后再释放子类自己申请的资源,这里没有申请资源,打印一句话意思一下。OK编译,错辣!!!

由于多态的原因,编译器会将一个类的析构函数名字都处理成“destructor”(后面再讲),所以子类的析构函数隐藏了父类的析构函数,编译器认为你调用的是子类的析构函数,形成死递归。解决方案:指定类域。

//-----------这是父类Person的析构-----------
~Person()
	{
		cout << "Person的析构" << endl;
	}
//---------------------------------------

~Student()
	{
		Person::~Person();
		cout << "Student析构" << endl;
	}

int main()
{
    Student s;
    return 0;
}

再次编译,没问题,运行。嘶~结果有问题

父类的析构函数怎么调用了两次啊!!! 

因为编译器在末尾会调用父类的析构函数,你自己显式调用一遍,编译器再调用一遍,所以一共调用了两次。


编译器这样特殊处理的原因是确保先析构子类,再析构父类。

因为子类析构函数中可以访问父类的成员,但若在执行这种语句之前前父类成员就被析构了,就会出问题;反过来父类的析构函数是访问不到子类成员的.,所以先把子类成员析构就没有影响。


编译器这样处理,就是告诉你,父类析构函数你不要显式调用啦,你只管先把子类申请的资源释放就OK,父类析构我帮你调用,这样就保证了析构安全.

//-----------这是父类Person的析构-----------
~Person()
	{
		cout << "Person的析构" << endl;
	}
//---------------------------------------

~Student()
	{
		cout << "Student析构" << endl;
	}

int main()
{
    Student s;
    return 0;
}

默认析构函数:先调用自定义类型的析构函数,然后调用父类的析构函数

值得注意的是,当你自己实现析构函数时,不允许显式调用自定义类型成员的析构函数,编译器会帮你隐式调用。

下节预告:菱形继承与虚继承。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构-----红黑树的插入

目录 前言 红黑树的储存结构 一、节点旋转操作 左旋&#xff08;Left Rotation&#xff09; 右旋&#xff08;Right Rotation&#xff09; 二、插入节点 1.插入的是空树 2.插入节点的key重新重复 3.插入节点的父节点是黑色 4.插入节点的父节点是红色 4.1父节点是祖父…

“之江创客”亚洲赛区完美收官 助力浙亚经贸高质量发展

10月13日下午&#xff0c;由商务部中国国际电子商务中心指导&#xff0c;浙江省商务厅等十个部门主办&#xff0c;浙江省电子商务促进中心承办的“之江创客”2023全球电子商务创业创新大赛亚洲赛区决赛成功举办。浙江省商务厅党组成员、副厅长张钱江出席活动并致辞&#xff0c;…

DDoS攻击与CC攻击:网络安全的两大挑战

在今天的数字时代&#xff0c;网络安全问题越来越突出&#xff0c;其中分布式拒绝服务攻击&#xff08;DDoS攻击&#xff09;和HTTP洪泛攻击&#xff08;CC攻击&#xff09;是两种常见的网络威胁。本文将探讨这两种攻击的概念、原理以及如何有效地应对它们。 1. DDoS攻击&…

Python的logging模块(日志、DEBUG、INFO、WARNING、ERROR、CRITICAL)

1. 前言 logging 是 Python 标准库中用于记录日志的模块。它提供了一种灵活且可配置的方式来在应用程序中记录各种信息&#xff0c;包括调试信息、警告和错误消息。无论是写框架代码还是业务代码&#xff0c;都离不开日志的记录&#xff0c;它能给我们定位问题带来极大的帮助。…

哈夫曼树的建立(C++,最优树)

介绍&#xff1a; 哈夫曼树&#xff08;Huffman Tree&#xff09;是一种用于数据压缩的树形数据结构。它是由刚特哈夫曼于1952年发明的。 哈夫曼树的特点是&#xff1a;对于一个长度为n的字符集&#xff0c;它可以将每个字符在树上表示为一个唯一的二进制编码。在哈夫曼树中&am…

C语言——编译全过程的那些事

C语言——编译全过程的那些事 一、C语言的编译过程二、编译的详细过程2.1预编译过程2.2编译过程2.3 汇编过程2.4链接过程 三、编译全过程 一、C语言的编译过程 1.C语言的编译过程通常可以分为两个大的部分&#xff0c;编译和链接。 2.在ANSI C的任何一种实现中&#xff0c;存…

Vue检测数据的原理

Vue能够对用户的数据进行响应式&#xff0c;也就是你在data中写了什么&#xff0c;你在模板中用到data的部分就会渲染成什么&#xff0c;那么Vue是怎么知道用户修改了data中的数据变化并对模板重新进行解析的呢&#xff1f; 在Vue将数据存储为自身的_data之前&#xff0c;Vue会…

《中国工业经济》企业数字化转型与供应链配置—集中化还是多元化

文章利用2010-2021年A股上市公司数据&#xff0c;从供应链治理角度系统验证了企业数字化转型对供应链配置的影响及其作用机制 研究发现&#xff0c;企业数字化转型显著降低了供应链上游供应商、下游客户以及供应链整体集中度&#xff0c;推动供应链配置多元化&#xff1b;该推…

python使用dataset快速使用SQLite

目录 一、官网地址 二、安装 三、 快速使用 一、官网地址 GitHub - pudo/dataset: Easy-to-use data handling for SQL data stores with support for implicit table creation, bulk loading, and transactions. 二、安装 pip install dataset 如果是mysql&#xff0c;则…

基于冠状病毒群体免疫优化的BP神经网络(分类应用) - 附代码

基于冠状病毒群体免疫优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于冠状病毒群体免疫优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.冠状病毒群体免疫优化BP神经网络3.1 BP神经网络参数设置3.2 冠…

7.memchr函数

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h>int main() {int* ans NULL;char arr[] "abcdef";int len 3;/*共查找len个字节*/char ch d;ans memchr(arr, ch, len);if (NULL ans){printf("前%d个字符中&#xff0c…

数据结构与算法课后题-第六章(图的基本概念)

文章目录 1 图的基本概念2 基本概念及术语1 有向图2 无向图3 简单图、多重图4 完全图5 子图6 连通 、连通图和连通分量7 强连通图、强连通分量8 生成树、生成森林 参考博客&#xff1a; 数据结构&#xff1a;图(Graph)【详解】 1 图的基本概念 2 基本概念及术语 1 有向图 2 无…

深度分析c+引用的本质以及引用与指针的区别

文章目录 引用的概念引用的定义引用的特性引用的权限问题引用的使用方式引用作参数引用作返回值指针的本质引用和指针的区别 引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用…

Oracle数据库SQL*Plus命令行执行SQL语句时,中文乱码报错解决方法

文章目录 问题背景解决方案1. 设置NLS_LANG环境变量2. 修改SQL*Plus字符集设置3. 使用Unicode字符集 常见错误和解决方法结语 &#x1f389;欢迎来到Java学习路线专栏~Oracle数据库SQL*Plus命令行执行SQL语句时&#xff0c;中文乱码报错解决方法 ☆* o(≧▽≦)o *☆嗨~我是IT陈…

【jmeter】接口测试流程

1、Jmeter简介 Jmeter是由Apache公司开发的一个纯Java的开源项目&#xff0c;即可以用于做接口测试也可以用于做性能测试。 Jmeter具备高移植性&#xff0c;可以实现跨平台运行。 Jmeter可以实现分布式负载。 Jmeter采用多线程&#xff0c;允许通过多个线程并发取样或通过独…

NTFS磁盘格式读写工具Tuxera NTFS 2023 for Mac中文破解版v2023含最新激活序列号

Tuxera NTFS 2023 Mac 是一个NTFS文件系统驱动程序&#xff0c;为解决Mac上不能对NTFS格式硬盘进行访问和读写而生。实现苹果Mac OS X系统读写Microsoft Windows NTFS文件系统&#xff0c;在硬盘、U盘等外接设备中进行全面访问、删除、修改等相关操作。 tuxera ntfs 2023 破解…

计算机网络第2章-CDN(4)

视频流和内容分发网 HTTP流和DASH 在HTTP流中&#xff0c;视频只是存储在HTTP服务器中作为一个普通的文件&#xff0c;每个文件有有一个特定的URL。当用户要看视频时&#xff0c;客户与服务器之间创建一个TCP连接并发送HTTP GET请求。 HTTP流具有严重缺陷&#xff0c;即所有…

扩大减产,NAND Flash市场迎来涨价潮 | 百能云芯

根据TrendForce的最新研究&#xff0c;NAND Flash市场即将面临一轮全面涨价的浪潮。供应商们通过严格控制产出量&#xff0c;将在第四季实施合约价的涨幅&#xff0c;预计在8%到13%之间。明年除非原厂仍能维持减产策略&#xff0c;且需留意服务器领域对Enterprise SSD需求是否回…

【Qt高阶】linux下编译提示找不到依赖的库【2023.10.16】

现象 提示找不到一些库文件。 排查方法 查看qmake出来的 makefile文件&#xff0c;相对路径是按照makefile文件所在路径进行查找。 命令行编译正常&#xff0c;拿QtCreator编译不过 把下面的勾去掉&#xff0c;直接在当前目录构建。

4.Vue-Vue调用第三方接口

题记 用vue调用第三方接口&#xff0c;以下是全部代码和操作流程。 寻找第三方接口网站 推荐&#xff1a;免费API - 提供免费接口调用平台 (aa1.cn) 下面的代码以下图中的接口为例 调用第三方接口代码 TestView.vue文件如下&#xff1a; <template> <div > <…