《C++继承详解:从入门到理解公有、私有与保护继承》


文章目录

  • 《C++继承详解:从入门到理解公有、私有与保护继承》
  • 一、继承的概念及定义
    • 1.1 继承的概念
    • 1.2 继承定义
      • 1.2.1 定义格式
      • 1.2.2 继承基类成员访问方式的变化
    • 1.3 继承类模版
  • 二、基类和派生类间的转换
  • 三、继承中的作用域
    • 3.1 隐藏规则
    • 3.2 考察继承作用域相关选择题
  • 四、派生类的默认成员函数
    • 4.1 4个常见的默认成员函数
    • 4.2 实现一个不能被继承的类
  • 五、继承与友元
  • 六、继承与静态成员
  • 七、多继承及其菱形继承问题
    • 7.1 继承模型
    • 7.2 虚继承
    • 7.3 IO库中的菱形虚拟继承
  • 八、继承和组合
  • 九、整体源代码


一、继承的概念及定义

1.1 继承的概念

在这里插入图片描述


在这里插入图片描述
在这里插入图片描述


在这里插入图片描述在这里插入图片描述


1.2 继承定义

1.2.1 定义格式

在这里插入图片描述在这里插入图片描述


1.2.2 继承基类成员访问方式的变化

在这里插入图片描述


在这里插入图片描述


1.3 继承类模版

继承类模版就是继承一个模版类,大框架和普通的继承想吐,但是调用父类中的属性或者行为时要指定在父类的哪个属性或者行为,这样是因为类模版的按需实例化,不指定就不会实例化,会报错
下面是用继承写一个栈,这个栈继承了父类vector
每次复用vector里面的成员函数时都要指定父类类域,否则报错,找不到标识符


在这里插入图片描述
在这里插入图片描述

二、基类和派生类间的转换

在这里插入图片描述在这里插入图片描述
在这里插入图片描述


三、继承中的作用域

3.1 隐藏规则

在这里插入图片描述在这里插入图片描述


3.2 考察继承作用域相关选择题

在这里插入图片描述

四、派生类的默认成员函数

4.1 4个常见的默认成员函数

在这里插入图片描述在这里插入图片描述


在这里插入图片描述


4.2 实现一个不能被继承的类

在这里插入图片描述

在这里插入图片描述


五、继承与友元

友元关系不能继承,也就是说基类友元不能访问派生类私有和保护成员
在这里插入图片描述


六、继承与静态成员

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


七、多继承及其菱形继承问题

7.1 继承模型

在这里插入图片描述


单继承和多继承
在这里插入图片描述


菱形继承: 会出现 二义性 和 数据冗余 的问题
在这里插入图片描述


在这里插入图片描述


7.2 虚继承

为了解决菱形继承的两个问题,这里使用虚继承,也就是在开始继承相同的基类的派生类后面加上virtual再加继承方式和基类
在这里插入图片描述在这里插入图片描述


我们可以设计出多继承,但是不建议设计出菱形继承,因为菱形虚拟继承以后,无论是使用还是底层都会复杂很多。当然有多继承语法支持,就一定存在会设计出菱形继承,像Java是不支持多继承的,就避开了菱形继承
在这里插入图片描述
在这里插入图片描述


7.3 IO库中的菱形虚拟继承

在这里插入图片描述


八、继承和组合

在这里插入图片描述


在这里插入图片描述


九、整体源代码

代码如下(示例):

#include<iostream>
using namespace std;//class Student
//{
//public:
//	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
//	void identity()
//	{
//		// ...
//	}
//	// 学习
//	void study()
//	{
//		// ...
//	}
//protected:
//	string _name = "peter"; // 姓名
//	string _address; // 地址
//	string _tel; // 电话
//	int _age = 18; // 年龄
//	int _stuid; // 学号
//};
//class Teacher
//{
//public:
//	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
//	void identity()
//	{
//		// ...
//	}
//	// 授课
//	void teaching()
//	{
//		//...
//	}
//protected:
//	string _name = "张三"; // 姓名
//	int _age = 18; // 年龄
//	string _address; // 地址
//	string _tel; // 电话
//	string _title; // 职称
//};
//int main()
//{
//	return 0;
//}//class Person
//{
//public:
//	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
//	void identity()
//	{
//		cout << "void identity()" << _name << endl;
//	}
//protected:
//	string _name = "张三";  // 姓名
//	string _address;       // 地址
//	string _tel;           // 电话
//	int _age = 18;         // 年龄
//};
//class Student : public Person
//{
//public:
//	// 学习
//	void study()
//	{
//		// ...
//	}
//protected:
//	int _stuid; // 学号
//};
//class Teacher : public Person
//{
//public:
//	// 授课
//	void teaching()
//	{
//		//...
//	}
//protected:
//	string title; // 职称
//};
//int main()
//{
//	Student s;
//	Teacher t;
//	s.identity();
//	t.identity();
//	return 0;
//}// 实例演⽰三种继承关系下基类成员的各类型成员访问关系的变化
//class Person
//{
//public:
//	void Print()
//	{
//		cout << _name << endl;
//	}
//protected:
//	string _name; // 姓名
//private:
//	int _age; // 年龄
//};
//
////class Student : protected Person
////class Student : private Person
//class Student : public Person
//{
//protected:
//	int _stunum; // 学号
//};#include<vector>
#include<stack>
//namespace ming
//{//template<class T>//class vector//{};// stack和vector的关系,既符合is-a,也符合has-a
//	template<class T>
//	class stack : public std::vector<T>
//	{
//	public:
//		void push(const T& x)
//		{
//			// 基类是类模板时,需要指定⼀下类域,
//			// 否则编译报错:error C3861: “push_back”: 找不到标识符
//			// 因为stack<int>实例化时,也实例化vector<int>了
//// 但是模版是按需实例化,push_back等成员函数未实例化,所以找不到
//			vector<T>::push_back(x);
//			//push_back(x);
//		}
//		void pop()
//		{
//			vector<T>::pop_back();
//		}
//		const T& top()
//		{
//			return vector<T>::back();
//		}
//		bool empty()
//		{
//			return vector<T>::empty();
//		}
//	};
//}
//int main()
//{
//	ming::stack<int> st;
//	st.push(1);
//	st.push(2);
//	st.push(3);
//	while (!st.empty())
//	{
//		cout << st.top() << " ";
//		st.pop();
//	}
//	return 0;
//}
//
//class Person
//{
//protected:
//	string _name; // 姓名
//	string _sex; // 性别
//	int _age; // 年龄
//};
//class Student : public Person
//{
//public:
//	int _No; // 学号
//};
//int main()
//{
//	Student sobj;
//	// 1.派⽣类对象可以赋值给基类的指针/引⽤
//	Person* pp = &sobj;
//	Person& rp = sobj;
//	// ⽣类对象可以赋值给基类的对象是通过调⽤后⾯会讲解的基类的拷⻉构造完成的
//	Person pobj = sobj;
//	//2.基类对象不能赋值给派⽣类对象,这⾥会编译报错
//	sobj = pobj;
//	return 0;
//}// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是⾮常容易混淆
//class Person
//{
//protected:
//	string _name = "⼩李⼦"; // 姓名
//	int _num = 111; // ⾝份证号
//};
//class Student : public Person
//{
//public:
//	void Print()
//	{
//		cout << " 姓名:" << _name << endl;
//		cout << " ⾝份证号:" << Person::_num << endl;
//		cout << " 学号:" << _num << endl;
//	}
//protected:
//	int _num = 999; // 学号
//};
//int main()
//{
//	Student s1;
//	s1.Print();
//	return 0;
//};
//
//class A
//{
//public:
//	void fun()
//	{
//		cout << "func()" << endl;
//	}
//};
//class B : public A
//{
//public:
//	void fun(int i)
//	{
//		cout << "func(int i)" << i << endl;
//	}
//};
//int main()
//{
//	B b;
//	b.fun(10);
//	b.fun();
//	return 0;
//};//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;
//}// C++98
//class Person
//{
//private:
//	Person(string name = "Peter")
//		:_name(name)
//	{}
//};
//
//// C++11
//class Person final
//{
//public:
//	Person(string name = "Peter")
//		:_name(name)
//	{}
//	~Person()
//	{
//		cout << "基类析构" << endl;
//	}
//};
//
//class Student;
//class Person
//{
//public:
//	friend void Display(const Person& p, const Student& s);
//protected:
//	string _name; // 姓名
//};
//class Student : public Person
//{
//protected:
//	int _stuNum; // 学号
//};
//void Display(const Person& p, const Student& s)
//{
//	cout << p._name << endl;
//	cout << s._stuNum << endl;
//}
//int main()
//{
//	Person p;
//	Student s;
//	// 编译报错:error C2248: “Student::_stuNum”: ⽆法访问 protected 成员
//	// 解决⽅案:Display也变成Student 的友元即可
//	Display(p, s);
//	return 0;
//}//class Person
//{
//public:
//	string _name;
//	static int _count;
//};
//int Person::_count = 0;
//class Student : public Person
//{
//protected:
//	int _stuNum;
//};
//int main()
//{
//	Person p;
//	Student s;
//	// 这⾥的运⾏结果可以看到⾮静态成员_name的地址是不⼀样的
//	// 说明派⽣类继承下来了,⽗派⽣类对象各有⼀份
//	cout << &p._name << endl;
//	cout << &s._name << endl;
//	// 这⾥的运⾏结果可以看到静态成员_count的地址是⼀样的
//	// 说明派⽣类和基类共⽤同⼀份静态成员
//	cout << &p._count << endl;
//	cout << &s._count << endl;
//	// 公有的情况下,⽗派⽣类指定类域都可以访问静态成员
//	cout << Person::_count << endl;
//	cout << Student::_count << endl;
//	return 0;
//}//class Person
//{
//public:
//	string _name; // 姓名
//};
//class Student : public Person
//{
//protected:
//	int _num; //学号
//};
//class Teacher : public Person
//{
//protected:
//	int _id; // 职⼯编号
//};
//class Assistant : public Student, public Teacher
//{
//protected:
//	string _majorCourse; // 主修课程
//};
//int main()
//{
//	// 编译报错:error C2385: 对“_name”的访问不明确
//	Assistant a;
//	a._name = "peter";
//	// 需要显⽰指定访问哪个基类的成员可以解决⼆义性问题,但是数据冗余问题⽆法解决
//	a.Student::_name = "xxx";
//	a.Teacher::_name = "yyy";
//	return 0;
//}//class Person
//{
//public:
//	string _name; // 姓名
//	/*int _tel;
//	* int _age;
//string _gender;
//string _address;*/
//// ...
//};
//// 使⽤虚继承Person类
//class Student : virtual public Person
//{
//protected:
//	int _num; //学号
//};
//// 使⽤虚继承Person类
//class Teacher : virtual public Person
//{
//protected:
//	int _id; // 职⼯编号
//};
//// 教授助理
//class Assistant : public Student, public Teacher
//{
//protected:
//	string _majorCourse; // 主修课程
//};
//int main()
//{
//	// 使⽤虚继承,可以解决数据冗余和⼆义性
//	Assistant a;
//	a._name = "peter";
//	return 0;
//}class Person
{
public:Person(const char* name):_name(name){}string _name; // 姓名
};
class Student : virtual public Person
{
public:Student(const char* name, int num):Person(name), _num(num){}
protected:int _num; //学号
};
class Teacher : virtual public Person
{
public:Teacher(const char* name, int id):Person(name), _id(id){}
protected:int _id; // 职⼯编号
};
// 不要去玩菱形继承
class Assistant : public Student, public Teacher
{
public:Assistant(const char* name1, const char* name2, const char* name3):Person(name3), Student(name1, 1), Teacher(name2, 2){}
protected:string _majorCourse; // 主修课程
};
int main()
{// 思考⼀下这⾥a对象中_name是"张三", "李四", "王五"中的哪⼀个?Assistant a("张三", "李四", "王五");return 0;
}template<class CharT, class Traits = std::char_traits<CharT>>
class basic_ostream : virtual public std::basic_ios<CharT, Traits>
{};
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_istream : virtual public std::basic_ios<CharT, Traits>
{};// Tire(轮胎)和Car(⻋)更符合has-a的关系
class Tire {
protected:string _brand = "Michelin"; // 品牌size_t _size = 17; // 尺⼨
};
class Car {
protected:string _colour = "⽩⾊"; // 颜⾊string _num = "陕ABIT00"; // ⻋牌号Tire _t1; // 轮胎Tire _t2; // 轮胎Tire _t3; // 轮胎Tire _t4; // 轮胎
};
class BMW : public Car {
public:void Drive() { cout << "好开-操控" << endl; }
};
// Car和BMW/Benz更符合is-a的关系
class Benz : public Car {
public:void Drive() { cout << "好坐-舒适" << endl; }
};
template<class T>
class vector
{};
// stack和vector的关系,既符合is-a,也符合has-a
template<class T>
class stack : public vector<T>
{};
template<class T>
class stack
{
public:vector<T> _v;
};
int main()
{return 0;
}

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

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

相关文章

佳能iR-ADV C5560复印机如何扫描文件到电脑

打印机与电脑连接首先&#xff0c;确保佳能iR-ADV C5560复印机通过USB或Wi-Fi等网络连接的方式成功连接到电脑。这可以通过USB线缆或Wi-Fi等网络来实现。连接完成后&#xff0c;便可利用打印机内置的扫描功能&#xff0c;轻松将文件扫描并传输至电脑中。【扫描操作步骤】接下来…

腾讯AI IDE

1.官网说明&#xff1a;打开腾讯AI IDE官网。2.安装说明&#xff1a;安装成功后的界面。3.登录 说明&#xff1a;通过邮箱和密码登录。4.成功说明&#xff1a;成功登录如下界面。5.简单一问说明&#xff1a;理解能力感觉不错。拥有Claude-3.7-Sonnet​​&#xff0c;​​Claude…

【LeetCode 热题 100】(一)哈希

1. 两数之和 class Solution {public int[] twoSum(int[] nums, int target) {int length nums.length;// 1.声明一个hashmap {nums[i], i}HashMap<Integer, Integer> map new HashMap<>();for (int i 0; i < length; i) {int second target - nums[i];if(m…

PMOS快速关断电路、PMOS加速关断电路

[电源系列]二、低成本MOS快速关断电路原理分析 MOS的减速加速电路设计 分享一个微碧在网上看到的电路情况 加速电路1 PMOS关断时间较长。 当用100kHz的频率驱动PMOS时&#xff0c;PMOS G极的电压信号并不是一个脉冲波&#xff0c;PMOS一直处于线性放大的状态&#xff0c;并且…

Docker笔记(基本命令、挂载本地gpu、Dockerfile文件配置、数据挂载、docker换源)

Docker 主要用于环境搭建以及服务部署 基本命令 1.查看镜像 docker images 2.查看容器 docker ps # 查看容器仅仅为查看运行状态的容器 docker ps -a # 查看所有状态的容器3.退出容器 exit4.删除镜像、容器 docker rm 镜像ID docker rm 容器ID docker rm -f 容器ID # 强制删除…

算法竞赛阶段二-数据结构(37)数据结构循环链表模拟实现

之前单链表中&#xff0c;数组全初始化为0&#xff0c;末尾最后一个next 存的就是0&#xff0c;指向的就是头节点循环链表的基本概念循环链表是一种特殊的链表&#xff0c;其尾节点的指针域指向头节点&#xff0c;形成一个闭环。与普通单链表相比&#xff0c;循环链表的遍历需要…

20250727让飞凌OK3576-C开发板在Rockchip的原厂Android14下通过耳机播音

20250727让飞凌OK3576-C开发板在Rockchip的原厂Android14下通过耳机播音 2025/7/27 23:28缘起&#xff1a;很容易知道 飞凌OK3576-C开发板 使用的声卡芯片是 NAU88C22YG 新唐科技(NUVOTON) NAU8822LYG NAU88C22YG 新唐立体声音频编解码芯片原理图&#xff1a;OK3576-C V1.2_202…

正向代理和反向代理的理解

**正向代理&#xff08;Forward Proxy&#xff09;和反向代理&#xff08;Reverse Proxy&#xff09;**是两种不同类型的代理服务器&#xff0c;它们在数据传输过程中扮演的角色、使用场景以及工作方式都有所不同。 正向代理&#xff08;Forward Proxy&#xff09; 定义与作用&…

Java 后端 Cookie Session Token会话跟踪技术

概述 会话从字面理解就是"两方交流"&#xff0c;那问题就来了&#xff0c;HTTP&#xff08;超文本传输协议&#xff09;里面的"传输"不就包含了"两方交流"的意思吗&#xff1f;为什么要多此一举提出会话技术呢&#xff1f; 谈到这个&#xff0c;…

智谱AI GLM大模型 GLM-4-Plus的快速使用 ChatOpenAI类来调用GLM-4模型

智谱AIGLM-4&#xff0c;2024年1月16日发布的第四代基座大模型&#xff0c;其整体性能相较前代提升近60%&#xff0c;多维度指标逼近OpenAI的GPT-4水平。该模型支持128K上下文窗口&#xff08;约300页文本处理能力&#xff09;&#xff0c;在长文本信息处理中实现100%精度召回。…

AsyncLocal浅复制的问题解决方案

针对C#中AsyncLocal<T>浅复制问题&#xff0c;以下是几种主要的解决方案&#xff1a; 1. 使用不可变对象&#xff08;推荐&#xff09; 将存储在AsyncLocal<T>中的对象设计为不可变的&#xff0c;避免修改共享状态&#xff1a; public class ImmutableUserContext …

IIS发布.NET9 API 常见报错汇总

记录工作过程中发现的IIS常见错误。 1. HTTP Error 500.19 - Internal Server Error .NET 9 API --》vs打包方式如下&#xff1a; 发布到IIS后报错HTTP Error 500.19 - Internal Server Error。 解决方案&#xff1a; 下载ASP.NET Core Hosting Bundle&#xff08;ASP.NET Co…

Google Chrome V8< 13.7.120 沙箱绕过漏洞

【严重】Google Chrome V8< 13.7.120 沙箱绕过漏洞 漏洞描述 V8 是 Google 开发的一款开源高性能 JavaScript 和 WebAssembly 引擎&#xff0c;广泛用于 Chrome 浏览器和 Node.js 等项目中。 受影响版本中&#xff0c;JsonParser::MakeString 函数在处理长度为 1 的转义字…

基于Spring Boot和Vue电脑维修平台整合系统的设计与实现

用户&#xff1a;注册&#xff0c;登录&#xff0c;在线报修&#xff0c;维修接单&#xff0c;维修报告&#xff0c;维修评价&#xff0c;个人资料维修工&#xff1a;登录&#xff0c;在线报修&#xff0c;维修接单&#xff0c;维修报告&#xff0c;维修评价&#xff0c;通知公…

InsightFace(RetinaFace + ArcFace)人脸识别项目(预训练模型,鲁棒性很好)

背景介绍 这是一个 简单的人脸识别项目&#xff0c;用 FastApi 在本地实现&#xff0c;使用预训练模型&#xff0c;直接可用。 新方案比之前的FaceNet强太多了&#xff0c;甚至不用数据增强等操作&#xff0c;就可以识别戴眼镜、不戴眼镜、歪着的人脸等。 充分证明了选型的重要…

App Inventor 2 使用 MaterialIcons 图标字体,快捷展示专业图标

平时布局的话&#xff0c;如果要使用图标&#xff0c;一般需要去找 png 图片&#xff0c;且透明背景的。如果需要根据不同常见图标进行变色的话&#xff0c;就需要准备多张不同样式的图标&#xff0c;还要考虑图片的分辨率等等因素&#xff0c;非常的麻烦。 这时&#xff0c;如…

C语言——关于指针(逐渐清晰版)

为了更好地理解本篇文章的知识内容&#xff0c;读者可以将以下文章作为补充知识进行阅读 &#xff1a; C语言————原码 补码 反码 &#xff08;超绝详细解释&#xff09;-CSDN博客 C语言————二、八、十、十六进制的相互转换-CSDN博客 C语言————斐波那契数列的理解…

SVG 在线编辑器

SVG 在线编辑器 引言 随着互联网技术的发展&#xff0c;矢量图形在网页设计和数据可视化中扮演着越来越重要的角色。SVG&#xff08;可缩放矢量图形&#xff09;因其文件小、无限缩放不模糊的特性&#xff0c;成为了网页设计中常用的图形格式。SVG 在线编辑器的出现&#xff0c…

libpostproc 已经从 ffmpeg 中移除,导致编译 ffmpeg 时没有 libpostproc

今天编译 ffmpeg 时突然发现 libpostproc 不见了&#xff0c;-enable-postproc 也变成了非法的选项。用搜索引擎搜索相关信息找不到一点&#xff0c;于是去 github 看。 从提交记录可以看到 libpostproc 已经被移除了 链接 主线中已经看不到了 libpostproc 这个目录了

基于 Dell PowerEdge T440 搭建的 Proxmox VE 配置 RTX 3060 显卡直通虚拟机、切换直通

基于 Dell PowerEdge T440 搭建的 Proxmox VE 配置 RTX 3060 显卡直通虚拟机、切换直通 文章目录 基于 Dell PowerEdge T440 搭建的 Proxmox VE 配置 RTX 3060 显卡直通虚拟机、切换直通 1. 前言 2. 前提条件 3. 配置步骤 3.1. 启用 VT-d 3.2. 激活 IOMMU 3.3. 添加 VFIO 模块 …