【C++初识继承】

图片名称

博主首页: 有趣的中国人
 

专栏首页: 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.mzph.cn/web/1207.shtml

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

相关文章

linux离线安装mysql

一、下载mysql 地址&#xff1a;MySQL 这里选择64为还是32为要根据操作系统来 uname -m 二、上传解压配置mysql 使用root账户登录linux服务器&#xff0c;在opt文件下创建mysql文件夹 cd /opt sudo mkdir mysql 使用Xftp上传mysql压缩包到此文件夹下(自行决定路径) cd mysql/…

基于Kubernetes集群构建MongoDB

基于Kubernetes集群构建MongoDB 作者:行癫(盗版必究) 一:基础环境 1.Kubernetes集群正常运行 2.Harbor私有仓库正常运行 二:MongoDB项目部署 ​ MongoDB项目对应Kubernetes的yaml文件: --- apiVersion: v1 kind: Namespace metadata:name: m

力扣:104. 二叉树的最大深度(Java,DFS,BFS)

目录 题目描述&#xff1a;输入&#xff1a;输出&#xff1a;代码实现&#xff1a;1.深度优先搜索&#xff08;递归&#xff09;2.广度优先搜索&#xff08;队列&#xff09; 题目描述&#xff1a; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从…

【QT进阶】Qt http编程之后端API测试工具postman使用介绍

往期回顾 【QT进阶】Qt Web混合编程之使用ECharts显示各类折线图等-CSDN博客 【QT进阶】Qt Web混合编程之实现ECharts数据交互动态修改-CSDN博客 【QT进阶】Qt http编程之http与https简单介绍-CSDN博客 【QT进阶】Qt http编程之后端API测试工具postman使用介绍 其实这个工具的…

Pytorch的下载安装

本文为自己整理的Pytorch下载相关的内容笔记&#xff0c;以便日后查阅 一. 基本命令 1.查看conda版本 conda --version2.创建conda新环境 conda create –n 名称 python版本3.查看已经创建的conda环境 conda info --envs4.进入虚拟环境 conda activate 环境名称 为了避免…

【Day 3】Ajax + Vue 项目、路由 + Nginx

1 Ajax Asynchronous JavaScript And XML 异步的 JavaScript 和 XML 作用&#xff1a; 数据交换 通过 Ajax 可以给服务器发送请求&#xff0c;并获取服务器响应的数据 异步交互 可以在不重新加载整个页面的情况下&#xff0c;与服务器交换数据并更新部分网页的技术&#xf…

【大模型应用极简开发入门(1)】LLM概述:LLM在AI中所处位置、NLP技术的演变、Transformer与GPT、以及GPT模型文本生成逻辑

文章目录 一. AI中大语言模型的位置与技术发展1. 从AI到Transformer2. NLP&#xff1a;自然语言处理3. LLM大型语言模型&#xff1a;NLP的一种特定技术3.1. LLM定义3.2. LLM的技术发展3.2.1. n-gram模型3.2.2. RNN与LSTM 二. Transformer在LLM中脱颖而出1. Transformer架构能力…

编译一个基于debian/ubuntu,centos,arhlinux第三方系统

目录 前言 准备工作 下载linux源码进行编译 linux源码下载 网站 问题 解决办法 编译 可能会遇到的问题 chroot下载debian环境 进入虚拟环境 把chroot的根目录文件打包为.gz文件 编译init文件&#xff08;用于系统启动时的一系列引导&#xff09; 给予文件夹权限 …

碎碎笔记01

凹凸性 一元函数 凸函数&#xff1a;二阶导数>0 f ( x ) x 2 f(x) x^2 f(x)x2的二阶导数是 2&#xff0c;>0凹函数&#xff1a;二阶导数<0 驻点&#xff0c;拐点 驻点&#xff1a;增减性的交替点 拐点&#xff1a;凹凸性的交替点 脑补 f ( x ) s i n x f(x) …

【树莓派学习】hello,world!

系统安装及环境配置详见【树莓派学习】系统烧录及VNC连接、文件传输-CSDN博客 树莓派内置python3&#xff0c;可以直接利用python输出。

Docker 部署 MongoDB 数据库

文章目录 官网地址docker 网络mongod.conf部署 MongoDB部署 mongo-expressdocker-compose.ymlMongoDB shell 官网地址 https://www.mongodb.com/zh-cn docker 网络 # 创建 mongo_network 网络 docker network create mongo_network # 查看网络 docker network list # 容器连…

Don‘t fly solo! 量化之路,AI伴飞

在投资界&#xff0c;巴菲特与查理.芒格的神仙友谊&#xff0c;是他们财富神话之外的另一段传奇。巴菲特曾这样评价芒格&#xff1a;他用思想的力量拓展了我的视野&#xff0c;让我以火箭的速度&#xff0c;从猩猩进化到人类。 人生何幸能得到一知己。如果没有这样的机缘&…

【C++初阶】List使用特性及其模拟实现

1. list的介绍及使用 1.1 list的介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前…

学习在Debian系统上安装Shadowsocks教程

学习在Debian系统上安装Shadowsocks教程 安装shadowsocks-libev及其所需的依赖启动Shadowsocks服务&#xff1a;如果你想要通过代理本地流量&#xff0c;你可以使用ss-local&#xff1a;启动并设置ss-local&#xff1a;查看状态本地连接 安装shadowsocks-libev及其所需的依赖 …

如何创建响应式HTML电子邮件模板

在这个适合初学者的指南中&#xff0c;你将学习如何创建一个响应式电子邮件模板。你将跟随逐步说明以及代码片段设计一个在任何设备上都看起来很棒的电子邮件模板。 这个项目非常适合渴望掌握电子邮件设计基础的新手&#xff01; &#xff08;本文视频讲解&#xff1a;java56…

力扣112,路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点 是指没有子节点…

Python 比较文本文件

1、问题背景 我们需要比较一个文本文件 F 与路径下多个其他文本文件之间的差异。我们已经编写了以下代码&#xff0c;但只能输出一个文件的比较结果。我们需要修改代码&#xff0c;以便比较所有文件并打印所有结果。 import difflib import fnmatch import osfilelist[] f op…

Lobechat 的基本使用流程

一、安装 下载lobechart的页面代码 $ git clone https://github.com/lobehub/lobe-chat.git $ cd lobe-chat $ pnpm install $ pnpm run dev注意&#xff1a;node环境要18以上 二、使用本地模型 1.安装ollama 2.通过ollama 下载本地模型 llama2&#xff08;选择合适的本地模型…

[阅读笔记16][Orca-2]Teaching Small Language Models How to Reason

接下来是Orca-2&#xff0c;这篇是微软在23年11月发表的论文&#xff0c;在Orca-1的基础上又进行了一些改进。 作者希望教会Orca-2各种推理策略&#xff0c;例如逐步思考、回忆然后回答、先回忆再推理再回答、直接生成回答等等策略。并且Orca-2应该能针对不同任务应该使用最合适…

【leetcode面试经典150题】64. 删除排序链表中的重复元素 II(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…