C++面向对象--------继承篇

目录

一.继承(重点)

1.1 概念

1.2 构造函数

1.2.1 派生类与基类的构造函数关系

1.2.2 解决方案

1.2.2.1 补充基类的无参构造函数

1.2.2.2 手动在派生类中调用基类构造函数

1.2.2.2.1 透传构造

1.2.2.2.2 委托构造

1.2.2.2.3 继承构造

1.3 对象的创建与销毁流程(掌握)

1.4 多重继承(掌握)

1.4.1 概念

1.4.2 可能出现的问题

1.4.2.1 问题1-重名问题(掌握)

1.4.2.2 问题2-菱形继承(熟悉)

二.权限

2.1 公有继承

2.2 保护继承

2.3 私有继承


一.继承(重点)

1.1 概念

继承是面向对象的三大特性之一,主要体现了代码复用的思想。

继承就是在一个已存在的类的基础上,建立一个新的类。并拥有其特性。

● 已存在的类被称为“基类”或者“父类”

● 新建立的类被称为“派生类”或者“子类”

#include <iostream>using namespace std;// 基类
class Father
{
private:string name = "孙";
public:void set_name(string name){this->name = name;}string get_name(){return name;}void work(){cout << "我的工作是厨师,我负责炒菜" << endl;}
};// 派生类
class Son:public Father // public:继承权限,基类的所有权限,在派生类中保持不变
{};int main()
{Son son;cout << son.get_name() << endl;son.work();return 0;
}
上面的代码,Son类的功能几乎与Father类重叠。在实际的开发使用过程中,派生类会做出一些与基类的差异化。

● 修改继承来的基类内容

○ 属性:1、公有属性可以直接改。更改后基类的属性也会改变,因为改的是同一份变量。私有属性,需要使用基类的公有函数进行更改。

○ 函数:函数隐藏,通过派生类实现一个同名同参数的函数,来隐藏基类的函数。

● 新增派生类的内容

#include <iostream>using namespace std;// 基类
class Father
{
private:string name = "孙";
public:void set_name(string name){this->name = name;}string get_name(){return name;}void work(){cout << "我的工作是厨师,我负责炒菜" << endl;}
};// 派生类
class Son:public Father // public:继承权限,基类的所有权限,在派生类中保持不变
{
public:void init(){
//        name = "王"; // 错误 基类的私有属性,派生类无法直接访问set_name("王");}void work(){cout << "我是程序猿,我在打代码" << endl;}void game(){cout << "我不光干活,我还打游戏,原神启动。杂交版启动" << endl;}
};int main()
{Son son;son.init();cout << son.get_name() << endl; // 王son.work(); // 我是程序猿,我在打代码son.game(); // 我不光干活,我还打游戏,原神启动。杂交版启动son.Father::work(); // 调用基类被隐藏的成员函数return 0;
}

基类与派生类是相对的,一个类可能存在又是基类又是派生类的情况,取决于那两个类进行比较。

1.2 构造函数

1.2.1 派生类与基类的构造函数关系

构造函数与析构函数不能被继承。

#include <iostream>using namespace std;// 基类
class Father
{
private:string name = "孙";
public:// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生类
class Son:public Father
{
public:};int main()
{
//    Son s; // 找不到基类的无参构造函数Son s("张"); // 没有匹配的构造函数return 0;
}

1.2.2 解决方案

1.2.2.1 补充基类的无参构造函数
#include <iostream>using namespace std;// 基类
class Father
{
private:string name = "孙";
public:// 补充基类无参构造函数Father(){cout << "构造函数被调用了" << endl;}// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生类
class Son:public Father
{
public:// 编译器自动添加的构造函数Son():Father(){cout << "派生类构造函数被调用了" << endl;}};int main()
{Son s; // 找不到基类的无参构造函数
//    Son s("张"); // 没有匹配的构造函数return 0;
}
1.2.2.2 手动在派生类中调用基类构造函数
1.2.2.2.1 透传构造

在派生类的构造函数中,调用基类的构造函数,实际上编译器自动添加的构造函数,调用基类无参构造函数时,采用的就是这种方式。

#include <iostream>using namespace std;// 基类
class Father
{
private:string name = "孙";
public:// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生类
class Son:public Father
{
public:// 透传构造Son():Father("张"){}// 派生类有参构造函数,调用基类有参构造函数Son(string fn):Father(fn){}
};int main()
{Son s;cout << s.get_name() << endl;Son s1("王");cout << s1.get_name() << endl;return 0;
}
1.2.2.2.2 委托构造

一个类的构造函数可以调用这个类的另一个构造函数,但是要避免循环委托。

委托构造的性能要低于透传构造,但是代码的维护性“更好”。因为通常一个类中构造函数都会委托给能力最强(参数最多)的构造函数,在代码重构时,只需要更改这个能力最强的构造函数即可。

#include <iostream>using namespace std;// 基类
class Father
{
private:string name = "孙";
public:// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生类
class Son:public Father
{
public:// 委托构造Son():Son("张"){}// 派生类有参构造函数,调用基类有参构造函数Son(string fn):Father(fn){}
};int main()
{Son s;cout << s.get_name() << endl;//    Son s1("王");
//    cout << s1.get_name() << endl;return 0;
}
1.2.2.2.3 继承构造

C++11 新增的写法,只需要一句话,就可以自动给派生类添加n(n为基类构造函数的个数(不包含默认无参构造函数))个构造函数。并且每个派生类的构造函数的格式都与基类相同,每个派生类的构造函数都通过透传构造调用对应格式的基类构造函数。

#include <iostream>using namespace std;// 基类
class Father
{
private:string name = "孙";
public:Father():Father("张"){}// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生类
class Son:public Father
{
public:using Father::Father;
//    // 委托构造
//    Son():Son(){}//    // 派生类有参构造函数,调用基类有参构造函数// Son(string fn):Father(fn){}
};int main()
{Son s;cout << s.get_name() << endl;//    Son s1("王");
//    cout << s1.get_name() << endl;return 0;
}

1.3 对象的创建与销毁流程(掌握)

在继承中,构造函数与析构函数的调用顺序

#include <iostream>using namespace std;
class Value
{
private:string str;
public:Value(string str):str(str){cout << str << "构造函数" << endl;}~Value(){cout << str <<"析构函数" << endl;}
};class Father
{
public:static Value s_value;Value val = Value("Father成员变量");Father(){cout << "Father 构造函数被调用了" << endl;}~Father(){cout << "Father 析构函数被调用了" << endl;}
};Value Father::s_value = Value("静态FatherValue被创建了");class Son:public Father
{
public:static Value s_value;Value val = Value("Son成员变量");   // int i = int(10);Son(){cout << "Son 构造函数被调用了" << endl;}~Son(){cout << "Son 析构函数被调用了" << endl;}
};Value Son::s_value = Value("静态SonValue被创建了");int main()
{cout << "主函数开始执行" << endl;{   // 局部代码块Son s;cout << "对象执行中" << endl;}cout << "主函数结束了" << endl;return 0;
}

上面的执行结果中,得到那些规律?

● 以对象执行中 为轴,上下对称。

● 在创建的过程中,同类型的内存区域,基类先开辟。对象创建:(先基类后派生类)。对象销毁(先派生类,后基类)。

● 静态的创建早于非静态。

1.4 多重继承(掌握)

1.4.1 概念

C++支持多重继承,即一个派生类可以有多个基类。派生类对于每个基类的关系仍然可以看作是一个单继承。

#include <iostream>using namespace std;class Sofa
{
public:void sit(){cout << "沙发可以坐着" << endl;}
};class Bed
{
public:void lay(){cout << "床可以躺着" << endl;}
};// 多重继承
class SofaBed :public Sofa,public Bed
{
public:
};int main()
{SofaBed sb;sb.lay();sb.sit();return 0;
}

1.4.2 可能出现的问题

1.4.2.1 问题1-重名问题(掌握)

当多个基类具有重名成员时,编译器在编译的过程中会出现二义性的问题。

解决方式:使用基类的类名::方式调用。

#include <iostream>using namespace std;class Sofa
{
public:void sit(){cout << "沙发可以坐着" << endl;}void clean(){cout << "打扫沙发" << endl;}
};class Bed
{
public:void lay(){cout << "床可以躺着" << endl;}void clean(){cout << "打扫床" << endl;}
};// 多重继承
class SofaBed :public Sofa,public Bed
{
public:
};int main()
{SofaBed sb;sb.lay();sb.sit();sb.Sofa::clean();sb.Bed::clean();return 0;
}
1.4.2.2 问题2-菱形继承(熟悉)

当一个基类有多个派生类,且这些派生类又有一个共同基类时。就会出现二义性问题,这种继承方式称为菱形(钻石)继承。

有两种解决方式:

1、使用基类的类名::方式调用

#include <iostream>using namespace std;// 家具厂
class Furniture
{
public:void func(){cout << "家具厂里有家具" << endl;}
};class Sofa:public Furniture
{
public:};class Bed:public Furniture
{
public:};// 多重继承
class SofaBed :public Sofa,public Bed
{
public:
};int main()
{SofaBed sb;sb.Bed::func();sb.Sofa::func();return 0;
}
2、使用虚继承(熟悉)

当出现虚继承时,Furniture类会生成一张虚基类表。这个表并不会占用任何对象的存储空间,属于Furniture类持有,在程序启动时加载进内存,表中记录了Furniture函数的调用地址偏移量。

Bed和Sofa对象会出现一个隐藏的成员变量指针,指向Furniture类中的虚基类表,占用对象四个字节。

SofaBed继承Sofa和Bed时,SofaBed类对象会同时拥有两个虚基类表指针成员,在调用时通过查表解决二义性。

#include <iostream>using namespace std;// 家具厂
class Furniture
{
public:void func(){cout << "家具厂里有家具" << endl;}
};class Sofa:virtual public Furniture
{
public:};class Bed:virtual public Furniture
{
public:};// 多重继承
class SofaBed :public Sofa,public Bed
{
public:
};int main()
{SofaBed sb;sb.func();return 0;
}

二.权限

类内

派生类中

全局

private

×

×

protected

×

public

2.1 公有继承

上面的代码中一直使用的就是公有继承,公有继承也是使用最多的一种继承方式。

在公有继承中,派生类可以继承基类的成员,但是不可以访问基类的私有成员,基类的公有成员与保护成员在派生类中权限不变。

2.2 保护继承

在保护继承中,派生类可以继承基类的成员,不可以访问基类的私有成员,基类的公有成员与保护成员在派生类中都是保护权限。(只能在基类和派生类中访问,外部无法访问)。

2.3 私有继承

在私有继承中,派生类可以继承基类的成员,但是不可以访问基类的私有成员,基类的公有成员与保护成员在派生类中权限都是私有权限。

#include <iostream>using namespace std;class Base
{
private:string str1 = "私有成员";
protected:string str2 = "保护成员";
public:string str3 = "公有成员";
};class Son:private Base
{
public:Son(){
//        cout << str1 << endl; // 错误str1为私有成员,派生类中无法访问cout << str2 << endl;cout << str3 << endl;}
};class Sun:public Son
{
public:Sun(){
//        cout << str1 << endl; // 错误str1为私有成员,派生类中无法访问
//        cout << str2 << endl; // 错误str2 在Son类中是私有成员,派生类无法访问
//        cout << str3 << endl; // 错误str3 在Son类中是私有成员,派生类无法访问}
};int main()
{Sun s1;
//    cout << s1.str1 << endl; // 错误,私有权限类外无法访问
//    cout << s1.str2 << endl; // 错误,私有权限类外无法访问
//    cout << s1.str3 << endl; // 错误,私有权限类外无法访问return 0;
}

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

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

相关文章

中标麒麟v5安装qt512.12开发软件

注意 需要联网操作 遇到问题1&#xff1a;yum提示没有可用软件包问题 终端执行如下命令 CentOS7将yum源更换为国内源保姆级教程 中标麒麟V7-yum源的更换&#xff08;阿里云源&#xff09; wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Cento…

mysql 慢查询日志slowlog

慢查询参数 slow log 输出示例 # Time: 2024-08-08T22:39:12.80425308:00 #查询结束时间戳 # UserHost: root[root] localhost [] Id: 83 # Query_time: 2.331306 Lock_time: 0.000003 Rows_sent: 9762500 Rows_examined: 6250 SET timestamp1723127950; select *…

PS证件照换底色

ps工具&#xff1a;Adobe Photoshop 2021 文章目录 1. 扣取人物2. 更换底色 1. 扣取人物 2. 更换底色

SwiftUI 6.0(iOS 18)自定义容器值(Container Values)让容器布局渐入佳境(上)

概述 我们在之前多篇博文中已经介绍过 SwiftUI 6.0&#xff08;iOS 18&#xff09;新增的自定义容器布局机制。现在&#xff0c;如何利用它们对容器内容进行“探囊取物”和“聚沙成塔”&#xff0c;我们已然胸有成竹了。 然而&#xff0c;除了上述鬼工雷斧般的新技巧之外&…

10月15日 -- 11月15日 ,参与《人工智能导论》学习打卡赢B站大会员

一、活动参与地址 点击链接进行活动报名>>>https://momodel.cn/classroom/course/detail?id6173911eab37f12b14daf4a8&activeKeyinfo&srcbef3adb478 二、活动详情 进入链接点击报名&#xff0c;仅需每天参与吴超老师的《人工智能导论》打卡活动&#xff0…

NPCAP和WPCAP

NPCAP是专为Windows开发的一款网络抓包SDK,该SDK提供了被应用程序调用的库文件和系统驱动程序。通过Npcap,我们可以得到原始网络数据,即未经过TCP/IP协议栈的数据,也就是网卡收到的数据,同时呢,我们也可以通过NPCAP设置接收过滤器,这样收到的数据就是我们感兴趣的数据,…

[C++ 核心编程]笔记 4.1.4 类和对象 - 案例1

类和对象: 案例1: 设计立方体类(Cube) 求出立方体的面积和体积分别用全局函数和成员函数判断两个立方体是否相等。 设计方法: 创建立方体类设计属性设计行为 求立方体面积和体积分别用全局和成员函数 判断立方体是否相等 #include<iostream> using namespace std;clas…

正则表达式-“三剑客”(grep、sed、awk)

1.3正则表达式 正则表达式描述了一种字符串匹配的模式&#xff0c;可以用来检查一个串是否含有某种子串&#xff0c;将匹配的子串替换或者从某个串中取出符号某个条件的子串等&#xff0c;在linux中代表自定义的模式模版&#xff0c;linux工具可以用正则表达式过滤文本。Linux…

★ C++进阶篇 ★ AVL树实现

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第五章----AVL树实现 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️澄岚主页&#xff1a;椎名澄嵐-CSDN博客C专栏&#xff1a;★ C进阶篇 ★_椎名澄嵐的博客-CSDN博客 ❄️…

Java基础:面向对象编程3

1 Java可变长参数 1.1 概述 Java 的可变长参数&#xff08;Varargs&#xff09;是在 Java 1.5 中引入的功能&#xff0c;允许方法接受任意数量的相同类型的参数。可变参数的语法是在参数类型后面加上三个点&#xff08;...&#xff09;&#xff0c;例如 int... numbers。 1.…

IPV6学习汇总

一、ICMPV6 ICMPv6&#xff08;Internet Control Message Protocol version 6&#xff09;&#xff0c;即互联网控制信息协议版本六&#xff0c;是为了与IPv6配套使用而开发的互联网控制信息协议。以下是关于ICMPv6的详细介绍&#xff1a; 一、基本功能 ICMPv6向源节点报告关…

半小时速通RHCSA

1-7章: #01创建以上目录和文件结构&#xff0c;并将/yasuo目录拷贝4份到/目录下 #02查看系统合法shell #03查看系统发行版版本 #04查看系统内核版本 #05临时修改主机名 #06查看系统指令的查找路径 #07查看passwd指令的执行路径 #08为/yasuo/ssh_config文件在/mulu目录下创建软链…

Vulnhub:DarkHole_2

一.信息收集/站点收集 &#xff08;1&#xff09;根据物理地址用nmap的主机发现功能得出IP地址 nmap -P 192.168.138.0/24 //同网段下主机发现得到IP为192.168.138.185&#xff08;2&#xff09;做nmap的目录扫描和端口扫描来发现其他站带以及信息 nmap -p- 192.168.138.185 …

什么是DApp?DApp开发指南

一、什么是DApp&#xff1f; DApp&#xff08;Decentralized Application&#xff09;&#xff0c;即去中心化应用&#xff0c;是一种基于区块链技术开发的应用程序&#xff0c;与传统的中心化应用不同&#xff0c;DApp不依赖单一服务器或管理主体&#xff0c;而是利用去中心化…

Oracle数据库安装Windows版本

1.下载压缩包 首先下载oracle19c的数据库&#xff0c;可以在官网下载&#xff0c;也可以从我的百度网盘下载。文件比较大&#xff0c;从oracle官网&#xff08;外网&#xff09;下载速度比较慢&#xff0c;还需要注册oracle用户。 通过网盘分享的文件&#xff1a;oracle数据库…

路由器概述

一、路由器的工作原理 根据路由表转发数据 二、路由表与其形成 2.1路由表 &#xff08;1&#xff09;概念 路由&#xff1a;从源主机到目的主机的转发过程路由表&#xff1a;路由器中维护的路由条目的集合&#xff1b;路由器根据路由表做路径选择 &#xff08;2&#xff…

k8s、prometheus、grafana数据采集和展示的链路流程

k8s集群中&#xff0c;容器级别的数据采集是由cAdvisor程序实现 cAdvisor # Container Advisor 容器顾问 cAdvisor程序是kubelet组件的一部分。 每个节点&#xff0c;包括master节点&#xff0c;都有一个kubelet系统服务&#xff0c; kukelet负责管理pod和容…

多台服务器分布式定时调度的几种方案

背景&#xff1a;现在有多个后端服务器&#xff0c;并且在代码中定义了一个定时任务&#xff0c;希望这个定时任务在一个时间只在一个服务器上执行&#xff0c;涉及到分布式调度&#xff0c;调研了一下总结出几种方案&#xff1a; 1.mysql的内置GET_LOCK GET_LOCK方法的介绍 …

TCP/IP相关

1、关于三次握手、四次挥手和TCP的11种状态&#xff1a; 记住这张图就行了&#xff1a; 2、关于慢启动、拥塞避免、超时重传、快速重传、快速恢复 记住这张图就行了&#xff1a; 一些名词解释&#xff1a; MSS&#xff1a;Maximum Segment Size&#xff0c;最大报文长度 RT…

[论文阅读]SCOTT: Self-Consistent Chain-of-Thought Distillation

中文译名&#xff1a;SCOTT: 思维链一致性蒸馏 会议&#xff1a;Proceedings of the 61st Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers) 链接&#xff1a;SCOTT: Self-Consistent Chain-of-Thought Distillation - ACL Antholo…