【C++初识继承】

news2024/12/26 23:15:14

图片名称

博主首页: 有趣的中国人
 

专栏首页: C++进阶
 


本篇文章主要讲解 继承 的相关内容


目录

1. 继承的概念和定义

1.1 继承的概念

 1.2 继承的定义

1.2.1 继承定义格式

1.2.2 继承方式与访问修饰限定符

2. 基类和派生类对象赋值转换

3. 继承中的作用域

3.1 全局域、局部域、类域、命名空间域

3.2 继承作用域

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

4.1 构造函数和拷贝构造

4.2 赋值重载和析构函数


1. 继承的概念和定义

1.1 继承的概念

在C++中,继承是一种机制,它允许一个类(称为子类或派生类)另一个类(称为父类或基类)获取成员变量和成员函数。子类可以继承父类的属性和行为,并且可以添加自己的属性和行为。这种继承关系可以用来建立类之间的层次结构,从而实现代码的重用和抽象。在C++中,继承有三种类型:公有继承、保护继承和私有继承,它们决定了父类的成员对子类的可见性。

using namespace std;
class Person
{
public:
	void Print()
	{
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
	}
protected:
	string name = "Jesicca";
	int age = 18;
};

// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了
Student和Teacher复用了Person的成员。下面我们使用监视窗口查看Student和Teacher对象,可
以看到变量的复用。调用Print可以看到成员函数的复用。

class Student : public Person
{
protected:
	int stu_id;
};

class Teacher : public Person
{
protected:
	int job_id;
};

int main()
{
	Student st;
	Teacher t;
	st.Print();
	t.Print();
	return 0;
}

 1.2 继承的定义

1.2.1 继承定义格式

1.2.2 继承方式与访问修饰限定符

 总的来说:

1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
都不能去访问它

class Person
{
public:
	void Print()
	{
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
	}
protected:
	string name = "Jesicca";
// age 为private类型,继承之后无论在派生类内还是类外都不能被访问
private:
	int age = 18;
};

class Student : public Person
{
public:
    // 这里会报错,age不能被访问
	void Stuage()
	{
		cout <<  "Student age:" << age << endl;
	}
protected:
	int stu_id = 20;
};

虽然不能被访问,但是实际上还是被继承了:

2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
派生类中能访问
,就定义为protected。可以看出保护成员限定符是因继承才出现的。

class Person
{
public:
	void Print()
	{
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
	}
protected:
	string name = "Jesicca";
    // age 变成了protected类型了
	int age = 18;
};

class Student : public Person
{
public:
    // 再类中能被访问
	void Stuage()
	{
		cout <<  "Student age:" << age << endl;
	}
protected:
	int stu_id = 20;
};

3. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
最好显示的写出继承方式。

4. 在实际运用中一般使用都是public继承几乎很少使用protetced/private继承,也不提倡
使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里
面使用。
 


2. 基类和派生类对象赋值转换

派生类对象可以赋值给基类的对象、基类的指针、基类的引用。这个操作叫做切片,

对于内置类型是直接拷贝,自定义类型调用拷贝构造,且切片过程中会进行赋值兼容不会产生临时变量

必须是基类的指针或者引用指向派生类才是安全的!

例如以下示例:

class Person
{
public:
	void Print()
	{
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
	}
	string name = "Jesicca";
protected:
	int age = 18;
};

class Student : public Person
{
public:
	void Stuage()
	{
		cout <<  "Student age:" << age << endl;
	}
protected:
	int stu_id = 20;
};
int main()
{
	Student st;
	// 派生类对象给基类对象
	Person p = st;
	// 派生类给基类指针
	Person* pst = &st;
	// 派生类给父类引用
	Person& ref = st;
	ref.name += "j";
	ref.Print();
	pst->name += "k";
	pst->Print();
	return 0;
}

3. 继承中的作用域

3.1 全局域、局部域、类域、命名空间域

先回顾以下C++中其他的域:

全局域、局部域、类域、命名空间域,

其中全局域和局部域会影响生命周期,但是类域和命名空间域不会影响生命周期,再同一个域中不能出现同名的成员变量,也不能出现非重载的两个同名函数

3.2 继承作用域

1. 在父类和派生类中可以定义两个同名的变量,因为父类和派生类是两个不同的作用域

2. 子类和父类如果有同名的变量,子类成员会屏蔽掉父类中同名的成员变量这叫做隐藏或者重定义,可以使用 基类::基类成员 进行显示访问

class Person
{
public:
	void Print()
	{
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
	}
	string name = "Jesicca";
protected:
	int age = 20;
};

class Student : public Person
{
public:
	void Stuage()
	{
        // 父类同名变量会被屏蔽,构成隐藏
		cout << "Stuage():" << age << endl;
        // 显示访问父类同名成员变量
		cout << "Personage:" << Person::age << endl;
	}
protected:
	int stu_id = 20;
	int age = 19;
};

 看以下这段代码:

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中的fun和A中的fun不是构成重载,因为不是在同一作用域
B中的fun和A中的fun构成隐藏成员函数满足函数名相同就构成隐藏。
 


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

默认构造是自己不写,编译器也能自动生成的:构造函数、拷贝构造、析构函数、赋值重载、取地址重载这些都是默认构造(在类和对象的文章中讲过)。

4.1 构造函数和拷贝构造

在派生类中,成员对象大体可以分为三大类:基类中继承下来的、自定义类型、内置类型

对于自定义类型还是调用在身的构造函数,内置类型不做处理。

对于基类中继承下来的成员,必须调用基类的构造函数初始化基类中的部分成员,如果基类中没有默认构造函数,那么必须在派生类的构造函数中显示调用基类的构造函数,不然就会报错。

例如以下的例子:

class Person
{
public:
    // 没有默认构造函数
	Person(const char* name)
		:name(name)
	{}
	void Print()
	{
		cout << "name:" << name << endl;
		//cout << "age:" << age << endl;
	}
protected:
	string name;
	//int age = 20;
};

class Student : public Person
{
public:
    // 由于基类中没有默认生成的构造函数,所以在派生类的构造函数必须显示调用基类的构造函数
	Student(const char* str, const char* name, int stu_id = 20, int age = 19)
        // 这边显示调用,类似于匿名对象的调用,要把基类看成一个整体进行调用
		:Person(name)
		,stu_id(stu_id)
		,age(age)
		,str(str)
	{}
	void Stuage()
	{
		cout << "Stuage():" << age << endl;
		//cout << "Personage:" << Person::age << endl;
	}
protected:
	string str;
	int stu_id;
	int age;
};

对于拷贝构造,派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化,例如:

// 父类
Person(const Person& p)
		:name(p.name)
	{}

// 子类
Student(const Student& st)
		:Person(st)
	{
		str = st.str;
		stu_id = st.stu_id;
		age = st.age;
	}

4.2 赋值重载和析构函数

 派生类的operator=必须要调用基类的operator=完成基类的复制。

Person& operator=(const Person& p)
{
	if (this != &p)
	{
		name = p.name;
	}
	return *this;
}



Student& operator=(const Student& st)
{
	if (this != &st)
	{
        // 这里如果写成operator=(st);会构成隐藏,会无穷递归
		Person::operator=(st);
		str = st.str;
		stu_id = st.stu_id;
		age = st.age;
	}
	return *this;
}

子类析构函数和父类析构函数构成隐藏关系。

派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
保证派生类对象先清理派生类成员再清理基类成员的顺序。

~Person()
{
	cout << "~Person()" << endl;
}

~Student()
{
	cout << "~Student()" << endl;
    // 会构成隐藏,因此如果写要显示写,
    // 但是为了保证析构的顺序是先子后父,编译器会在程序结束时自动调用父类的析构函数,不需要显示写,        
    // 因为在此时可能需要访问父类中的对象,如果析构就访问不了了
	//Person::~Person();
}

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

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

相关文章

NIMAX下载安装使用,pyvisa基本使用

NIMAX部分&#xff1a; 1、先在NI官网下载系统配置和NI-VISA&#xff1a; 系统配置&#xff1a; https://www.ni.com/zh-cn/support/downloads/drivers/download.system-configuration.html#532687https://www.ni.com/zh-cn/support/downloads/drivers/download.system-conf…

机器学习基本流程

Jupyter Notebook 代码连接&#xff1a; machine_learning_demo machine_learning_ensembles Step 1: Imports and Configuration import pandas as pd import numpy as np import copy import json import pickle import joblib import lightgbm as lgb import optuna impor…

IDEA插件:CodeGeex

前言 CodeGeeX是由清华大学和智谱AI联合开发的多语言代码生成模型。CodeGeeX是一款AI编程助手&#xff0c;其功能类似于Github Copilot、Codeium、CodeWhisperer、Bito等智能编程助手。CodeGeeX支持Python、C、Java、JavaScript、Go等10多种主流编程语言。它可以帮助程…

【小程序】IOS wx小程序解压获取源文件

根据自己手机的系统&#xff0c;获取wx小程序的缓存目录 一、微信小程序文件存放路径 安卓&#xff1a; /data/data/com.tencent.mm/MicroMsg/{{user哈希值}}/appbrand/pkg/iOS越狱&#xff1a; /User/Containers/Data/Application/{{系统UUID}}/Library/WechatPrivate/{{user…

unity学习(89)——unity塞满c盘!--删除editor下的log文件

卸了一个视频后强制续命打开详细信息&#xff1a; 这个再往下找也是没用的&#xff01; 显示隐藏文件夹后&#xff01;执行如下操作&#xff01; 30个g&#xff01; 其中unity占23g editer占了21g 删除C:\Users\王栋林\AppData\Local\Unity\Editor下的log文件 恢复到之前的水…

建筑楼宇VR火灾扑灭救援虚拟仿真软件厂家

在传统消防安全教育方式中&#xff0c;往往存在内容枯燥、参与度低和风险大等问题&#xff0c;使得消防安全知识难以深入人心。然而&#xff0c;借助VR消防安全逃生教育系统&#xff0c;我们可以打破这一困境&#xff0c;为公众带来前所未有的学习体验。 VR消防安全逃生教育系统…

【后端】Thymeleaf模板引擎学习笔记

文章目录 1. java体系模板引擎介绍2. 使用2.1 初步使用 视频地址 1. java体系模板引擎介绍 FreeMarkerThymeleafVelocity 2. 使用 2.1 初步使用 引入依赖 <dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf</artifactId><…

SpringBoot学习之Kafka下载安装和启动(三十三)

一、Mac环境 1、下载Kafka&#xff1a;Apache Kafka 2、这里我选择的版本是kafka_2.12-3.7.0&#xff0c;下载最新版的Kafka二进制文件&#xff0c;解压到你喜欢的目录&#xff08;建议目录不要带中文&#xff09;。 3、启动ZooKeeper服务&#xff0c;Kafka需要使用ZooKeeper&…

Claude 3 Opus 效果是否真的可以超过GPT-4?

实测,不仅是超过,而且我个人感觉这个差距甚至大于GPT3.5到GPT4的距离. claude3在长篇理学论文的解析能力是非常显著的,可以扩展补完作者省略的大量运用高等数学,复变函数以及更多数理方法的计算过程,并且将中间过程补完的非常完美.不会漏符号,错符号,偏差数值之类的问题.工科许…

【网站项目】党员之家服务系统小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【BUG】前端|GET _MG_0001.JPG 404 (Not Found),hexo博客搭建过程图片路径正确却找不到图片

我的问题 我查了好多资料&#xff0c;结果原因是图片名称开头是_则该文件会被忽略。。。我注意到网上并没有提到这个问题&#xff0c;遂补了一下这篇博客并且汇总了我找到的所有解决办法。 具体检查方式&#xff1a; hexo生成一下静态资源&#xff1a; hexo g会发现这张图片…

嵌入式linux中利用QT控制蜂鸣器方法

大家好,今天给大家分享一下,如何控制开发板上的蜂鸣器。 第一:开发板原理图 从原理图中可以得出,当引脚输出低电平的时候,对应的蜂鸣器发出响声。 第二:QT代码详细实现 设置一个按钮,点击即可控制BEEP状态发生反转。 #ifndef MAINWINDOW_H #define MAINWINDOW_H#in…

专题【二分查找】刷题日记

题目列表 4. 寻找两个正序数组的中位数 33. 搜索旋转排序数组 34. 在排序数组中查找元素的第一个和最后一个位置 35. 搜索插入位置 69. x 的平方根 167. 两数之和 II - 输入有序数组 209. 长度最小的子数组 222. 完全二叉树的节点个数 287. 寻找重复数 2023.04.14 4. 寻找两…

STM32G431RBT6之时钟树配置与生成工程

默认大家都下载了蓝桥杯嵌入式资源包了哈. 首先,打开cubumx,修改RCC与SYS. 打开并观察原理图,发现晶振是24Mhz. 第一步,打开Clock Configuration. 第二步,修改晶振为原理图相对应的24Mhz. 第三步,切换到HSE. 第四步,切换到PLLCLK. 第五步,设置HCLK为80Mhz(15届真题要求为8…

【银角大王——Django课程——ORM】

Django课程——ORM框架 Django 模型使用自带的 ORMORM 解析过程:ORM 对应关系表&#xff1a;下载mysqlclient安装包创建数据库——ORM只能操作表&#xff0c;无法创建数据库。连接数据库——修改settings中的DATABASESDjango操作表&#xff0c;在models.py文件中编写——操作表…

数字接龙(蓝桥杯)

文章目录 数字接龙【问题描述】解题思路DFS 数字接龙 【问题描述】 小蓝最近迷上了一款名为《数字接龙》的迷宫游戏&#xff0c;游戏在一个大小为N N 的格子棋盘上展开&#xff0c;其中每一个格子处都有着一个 0 . . . K − 1 之间的整数。游戏规则如下&#xff1a; 从左上…

专利基础概念

专利是一种知识产权形式&#xff0c;它为发明创造提供了一种法律保护机制&#xff0c;允许发明者在一定期限内对其发明享有独占权。 1、专利类型 专利类型&#xff0c;也被称为专利的客体&#xff0c;是指符合专利授予条件的各种发明创造。根据中国专利法&#xff0c;发明创造…

【经典小游戏】猜数字

前言1. 游戏介绍2. 游戏实现3. 游戏优化结语 个人主页&#xff1a;C_GUIQU 前言 各位小伙伴大家好&#xff01; 先问大家一个问题&#xff1a;我们为什么要学习&#xff1f; 简单来说&#xff0c;就是为了实践&#xff01;只有不断学习才可以帮助我们更好地实践&#xff01; 小…

【Java网络编程】网络编程中的基本概念及实现UDP、TCP客户端服务器程序

目录 一、什么是网络编程&#xff1f; 二、网络编程中的基本概念 1. 客户端和服务器 2. 请求和响应 三、Socket套接字 UDP数据报套接字编程 1. DatagramSocket 2. DatagramPacket 3. UDP回显客户端服务器程序 4. UDP字典客户端服务器程序 TCP流套接字编程 1. Serve…

【JS】js数字转k、w结尾 | 1000 = 1k

问题 数字转k、w结尾 如&#xff1a;10001k 100001w 码 /*** 数字转k,w* param {Number} num * returns String*/ const numberTokw num > {if (num < 1000) return numlet endStr w,numVal 10000;if (num > 999 && num < 10000) {endStr knumVal …