C++之继承<2>【详解】

news2024/11/15 23:34:06

C++之继承<2>【详解】

  • 1. 派生类的默认成员函数
    • 1.1 1. 构造成员函数
    • 1.2 拷贝复制
    • 1.3 构造函数和析构函数的执行顺序
  • 2. 继承和友元
  • 3. 继承与静态成员

1. 派生类的默认成员函数

1.1 1. 构造成员函数

  派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

  无论是否显示的调用基类的构造成员函数,都会自动调用基类的默认成员函数:

#include <iostream>
using namespace std;
class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}
	
	string _name; 
};


class Student : public Person
{
public:
	Student(const char* name, int num)
		: _num(num)
	{
		cout << "Student()" << endl;
	}
protected:
	int _num; 
};
int main()
{
	Student s1("jack", 18);
	return 0;
}

没有显示调用
显示调用后:
在这里插入图片描述

上述的后半段的意义是:如果基类没有默认的构造函数,那么是这样的:

	Person(const char* name = "peter")
		: _name(name)
	{}

  可以进行传参来构造对象,如果你在派生类没有显示的调用它,那么不能进行进行传参来构造。

#include <iostream>
using namespace std;

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}
	
	string _name; 
};


class Student : public Person
{
public:
	Student(const char* name, int num)
		: _num(num)
	{
		cout << "Student()" << endl;
	}
protected:
	int _num; 
};
int main()
{
	Student s1("jack", 18);	
	cout << s1._name; 
	return 0;
}

在这里插入图片描述
上图可以看到,传入的参数是“jack”, 但是构造出来的对象属性是“peter”。
  至于必须在初始化列表显示的调用,是因为祖师爷定下的规则是,先构造基类再构造派生类,初始化列表是先于构造函数执行的。
  Person(name)在初始化列表中的顺序可以随意改动的,因为初始化列表的执行顺序只跟声明的顺序有关,跟初始化列表中的先后顺序无关。

1.2 拷贝复制

分别是拷贝构造函数和operator=复制函数:

  1. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  2. 派生类的operator=必须要调用基类的operator=完成基类的复制。

上面两条的原因和构造函数的一样,就不在赘述。
下面是验证的代码:

#include <iostream>
using namespace std;

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}
	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}
	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)//防止复制相同的对象,相同的就不必进行下面步骤了
			_name = p._name;
		return *this;
	}
protected:
	string _name; // 姓名
};



class Student : public Person
{
public:
	Student(const char* name, int num)
		: Person(name)
		, _num(num)
	{
		cout << "Student()" << endl;
	}
	Student(const Student& s)
		: Person(s)
		, _num(s._num)
	{
		cout << "Student(const Student& s)" << endl;
	}

	
	Student& operator = (const Student& s)
	{
		cout << "Student& operator= (const Student& s)" << endl;
		if (this != &s)//防止复制相同的对象,相同的就不必进行下面步骤了
		{
			Person::operator =(s);
			_num = s._num;
		}
		return *this;
	}
protected:
	int _num; //学号
};
int main()
{
	Student s1("jack", 18);
	Student s2(s1);
	return 0;
}

1.3 构造函数和析构函数的执行顺序

  1. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
  2. 派生类对象初始化先调用基类构造再调派生类构造。
  3. 派生类对象析构清理先调用派生类析构再调基类的析构。
  • 首先,为什么一定先调用基类构造函数再调用派生类的的构造函数呢?
      如果你先调用派生类的构造函数,派生类是继承基类的,那么派生类中就可以使用基类中的属性和行为,但是此时还没有调用基类的构造函数,所以不能这样。

  • 为什么一定先调用派生类的析构函数再调用基类的析构函数呢?
      如果先调用基类的析构函数的话,会释放掉一些变量或指针,那么派生类使用继承过来的这些变量或者指针的时候,它们已经变成了野指针,因此不能如此。

在这里插入图片描述

下面是完整代码,大家可以尝试验证:

#include <iostream>
using namespace std;

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}
	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}
	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;
		return *this;
	}
	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};



class Student : public Person
{
public:
	Student(const char* name, int num)
		: Person(name)
		, _num(num)
	{
		cout << "Student()" << endl;
	}
	Student(const Student& s)
		: Person(s)
		, _num(s._num)
	{
		cout << "Student(const Student& s)" << endl;
	}

	
	Student& operator = (const Student& s)
	{
		cout << "Student& operator= (const Student& s)" << endl;
		if (this != &s)
		{
			Person::operator =(s);
			_num = s._num;
		}
		return *this;
	}

	
	~Student()
	{
		cout << "~Student()" << endl;
	}
protected:
	int _num; //学号
};
int main()
{
	Student s1("jack", 18);
	Student s2(s1);
	Student s3("rose", 17);
	s1 = s3;
	return 0;
}

2. 继承和友元

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员

#include <iostream>
using namespace std;

class Student;
class Person
{
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name = "zhangsan"; // 姓名
};



class Student : public Person
{
public:
	
protected:
	int _num; //学号
};

void Display(const Person& p, const Student& s)
{
	cout << p._name << endl;
	cout << s._num << endl;
}
int main()
{
	Student s;
	Person p;
	Display(p, s);
	return 0;
}

在这里插入图片描述

从上面图中可以看出。

3. 继承与静态成员

  基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。

#include <iostream>
#include <string>
using namespace std;


class Person
{
public:
	Person()
	{
		++_count;
		++age;
	}


public:
	static int _count;
	int  age = 0; // 姓名
};
int Person::_count = 0;


class Student : public Person
{
public:

protected:
	int _num; //学号
};

int main()
{
	Student s;
	Person p;
	cout << "Person::_count:  "<<Person::_count<<endl;
	cout << "Person::age:  "<<p.age<<endl;
	return 0;
}

运行结果是:
在这里插入图片描述

  由此可见,静态成员_count是共有的,只有一个。


  😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

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

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

相关文章

力扣刷题 day50:10-20

1.存在重复元素 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 &#xff0c;返回 true &#xff1b;如果数组中每个元素互不相同&#xff0c;返回 false 。 方法一&#xff1a;集合去重 #方法一&#xff1a;集合去重 def containsDuplicate(nums):return len(n…

八股总结(招聘)

线程创建方法&#xff1a; 继承 Thread 类实现 Runnable 接口通过 ExecutorService 和 Callable\ 实现有返回值的线程基于线程池的execute()&#xff0c;创建临时线程

嵌入式面试常见问题(二)

1.malloc如何分配内存&#xff1f; 进行虚拟地址空间的分布&#xff1a;程序地址空间-》程序虚拟地址空间-》进程虚拟地址空间 内存布局&#xff1a; ​ 进程虚拟地址空间和PCB&#xff08;Process Control Block&#xff0c;进程控制块&#xff09;进行串联 &#xff1a; ​…

微信小程序进阶——后台交互

目录 一、后台准备 1.1 pom.xml 1.2 配置数据源 1.3 整合mybatis 二、前后端交互 2.1 method1 2.2 method2 2.2.1 封装request 2.2.2 头部引用util 2.2.3 编写方法 2.2.4 展示效果 三、WXS的使用 3.1 会议状态 3.1.2 引入wxs 3.1.3 修改代码 3.1.4 展示效果 3…

计算机毕业设计 基于SpringBoot笔记记录分享网站的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Mysql 中的性能调优方法

Mysql 性能调优方法可以从四个方面来说&#xff0c;分别是&#xff1a; 表结构与索引 SQL 语句优化 Mysql 参数优化 硬件及系统配置 这四个方面的优化成本和优化效果是成反比的。 表结构和索引的优化 表结构和索引的优化&#xff0c;主要可以下面这些方面去优化&#xff1a; 分…

NewStarCTF 2023 公开赛道 WEEK2|WEB 游戏高手

app_v2.js就是游戏文件 右键“用调试器打开”&#xff1a; var gameScore 0; 就是当前分数&#xff0c; 打开控制台&#xff0c;输入 gameScore 1000000&#xff0c;回车 就可以得到flag

字节码进阶之ASM字节码操作类库详解

文章目录 0.前言1. 引言2. ASM简介3. 字节码基础知识回顾 4. ASM的核心概念5. ASM的基本用法5.1. 读取和分析字节码5.2. 修改和生成字节码 6. ASM的高级用法6.1. 字节码增强技术6.2. 自定义类加载器和类定义 7. 实例演示&#xff1a;使用ASM实现简单的字节码增强 字节码进阶之A…

代码随想录算法训练营第二十八天丨 回溯算法part04

491.递增子序列 思路 这个递增子序列比较像是取有序的子集。而且本题也要求不能有相同的递增子序列。 在90.子集II (opens new window)中是通过排序&#xff0c;再加一个标记数组来达到去重的目的。 而本题求自增子序列&#xff0c;是不能对原数组进行排序的&#xff0c;排…

前端工作方式要换了?HTMX简介:无需JavaScript的动态HTML

HTMX允许你使用扩展的HTML语法代替 JavaScript 来实现交互性。HTMX 在标记中直接为你提供HTTP 交互&#xff0c;并支持许多其他交互需求&#xff0c;无需求助于 JavaScript。这是一个有趣的想法&#xff0c;可能最终会影响到web前端的工作方式。让我们看看如何使用HTMX以及它的…

pytorch 入门 (三)案例一:mnist手写数字识别

本文为&#x1f517;小白入门Pytorch内部限免文章 &#x1f368; 本文为&#x1f517;小白入门Pytorch中的学习记录博客&#x1f366; 参考文章&#xff1a;【小白入门Pytorch】mnist手写数字识别&#x1f356; 原作者&#xff1a;K同学啊 目录 一、 前期准备1. 设置GPU2. 导入…

聊聊分布式架构09——分布式中的一致性协议

目录 01从集中式到分布式 系统特点 集中式特点 分布式特点 事务处理差异 02一致性协议与Paxos算法 2PC&#xff08;Two-Phase Commit&#xff09; 阶段一&#xff1a;提交事务请求 阶段二&#xff1a;执行事务提交 优缺点 3PC&#xff08;Three-Phase Commit&#x…

kubeadm初始化搭建cri-dockerd记录 containerd.io

07.尚硅谷_搭建K8s集群&#xff08;kubeadm方式&#xff09;-部署master节点_哔哩哔哩_bilibili 视频里的版本只有1.17而现在&#xff08;2023.10.20&#xff09;kubernetes最新版本是1.28&#xff0c;需要搭载cri-dockerd&#xff0c; 先去网站下载了对应的rpm包cri-dockerd…

计算机算法分析与设计(14)---贪心算法(会场安排问题和最优服务次序问题)

文章目录 一、会场安排问题1.1 问题描述1.2 思路分析1.3 例题分析1.4 代码编写 二、最优服务次序问题2.1 问题描述2.2 思路分析2.3 代码编写 一、会场安排问题 1.1 问题描述 假设在足够多的会场里安排一批活动&#xff0c;并希望使用尽可能少的会场。设计一个有效的贪心算法进…

kettle 导出Excel 日期信息为空bug

今天做个需求&#xff0c;跨库联表查询数据。导出为Excel &#xff0c;但是日期数据除了问题。日期yyyy/mm/dd hh:mm:ss 竟然是空的 。 解决办法&#xff1a; 一、&#xff08;网上给出最多的解决方案&#xff0c;但本人不实用。需要安装MySQL监听&#xff09; to_char(日期,…

Mojo——会燃的 AI 编程语言

点击链接了解详情 导语&#xff1a;本文简介 Mojo 的背景与特点&#xff0c;并分享如何通过腾讯云 Cloudstudio 的 WebIDE 和分享社区快速学习和上手 Mojo。 &#x1f525;&#x1f525;&#x1f525; 腾讯云 Cloud Studio 已开放 Mojo 应用模版。 什么是 Mojo Mojo 是基于 P…

CodeFormer和GFPGAN的本地部署与效果对比

CodeFormer和GFPGAN是两个图片人脸修复的开源程序&#xff0c;两个程序不相伯仲&#xff0c;效果都非常棒&#xff0c;在stable diffusion中这两个插件都有集成进去&#xff01;我们今天就将这两个程序的本地独立安装和使用方法记录一下&#xff01; CodeFormer github主页地址…

【前端】使用tesseract插件识别提取图片中的文字

前言 有时候项目需要识别证照信息&#xff0c;或者拍照搜索内容等。图片处理一般是后端处理比较好&#xff0c;不过前端也有相关插件处理&#xff0c;tesseract.js就是一种前端处理方案。 使用tesseract tesseract更多的语言模型&#xff1a;language配置 安装 Tesseract.…

react中JSX基础与useState的基本使用 + 评论显示删除需求案例

参考视频&#xff1a;https://www.bilibili.com/video/BV1ZB4y1Z7o8/?p3&spm_id_frompageDriver&vd_source5c584bd3b474d579d0bbbffdf0437c70 如果没有安装create-react-app需要先全局安装 命令&#xff1a;npm i -g create-react-app1.快速搭建开发环境 create-re…

国内有哪些做得好的企业协同办公软件

在当今信息化时代&#xff0c;企业协同办公软件成为了提升企业效率和推动协作的重要工具。国内市场涌现出许多优秀的企业协同办公软件&#xff0c;为企业提供了高效、便捷的协同办公解决方案。在本文中&#xff0c;我们将向大家介绍3款在国内好评如潮的企业协同办公软件&#x…