C++【继承】

news2024/11/25 13:50:43

✨个人主页: 北 海
🎉所属专栏: C++修行之路
🎃操作环境: Visual Studio 2019 版本 16.11.17

成就一亿技术人


文章目录

  • 🌇前言
  • 🏙️正文
    • 1、继承的概念
      • 1.1、本质
      • 1.2、作用
      • 1.3、实际例子
    • 2、继承的定义
      • 2.1、格式
      • 2.2、权限
      • 2.3、使用
    • 3、继承的作用域
      • 3.1、隐藏
    • 4、基类与派生类对象的赋值转换
      • 4.1、切片
    • 5、派生类的中的默认成员函数
      • 5.1、隐式调用
      • 5.2、显式调用
    • 6、继承与友元函数
    • 7、继承与静态成员
    • 8、菱形继承
      • 8.1、概念
      • 8.2、现象
      • 8.3、原因
      • 8.4、解决方法
    • 9、补充
  • 🌆总结


🌇前言

继承 是面向对象三大特性之一(封装、继承、多态),所有的面向对象(OO)语言都具备这三个基本特征,封装相关概念已经在《类和对象》系列中介绍过了,今天主要学习的是 继承,即如何在父类的基础之上,构建出各种功能更加丰富的子类

王阿姨(父类)的两个孩子(子类),在父类的基础之上,衍生出了不同的特性

继承


🏙️正文

1、继承的概念

什么是继承?继承遗产还是继承花呗?答案都不是,先来看看官方解释:继承(inheritance)机制是面向对象程序设计使代码可以复用的重要的手段,它允许程序员在保持原有基类(父类)特性的基础上进行扩展,增加功能,这样产生新的类,称为派生类(子类)

继承花呗

继承相关概念:

  • 被继承对象:父类 / 基类 (base
  • 继承方:子类 / 派生类 (derived

1.1、本质

继承的本质就是 复用代码

假设你现在需要写一个 学校教务系统,单从角色划分上来说,可以简单分为:教职工和学生 这两大类,但如果继续划分的话,还可以分出:校领导、各级院长、辅导员、后勤人员、大一/大二/大三/大四学生等,假设为每种不同的角色都设计一个 struct,那么这个工程量也未免太大了

为了复用代码、提高开发效率,可以从各种角色中选出共同点,组成 基类,比如每个 都有姓名、年龄、性别、联系方式等基本信息,而 教职工学生 的区别就在于 管理与被管理,因此可以在 基类 的基础上加一些特殊信息如教职工号 表示 教职工,加上 学号 表示学生,其他细分角色设计也是如此

这样就可以通过 继承 的方式,复用 基类 的代码,划分出各种 子类

继承

1.2、作用

子类基础父类后,可以享有父类中的所有 公开 / 保护 属性,也就是说,除了 私有 内容外,父类有的,子类全都有

示例:在 父类-车 的基础上,派生出 越野车 和 跑车 这两个 子类

//父类-车
class Car
{
public:
	Car(int speed = int())
		:_speed(speed)
	{}

	int getSpeed()
	{
		return _speed;
	}

private:
	int _speed;
};

//子类-越野车
class SUV : public Car
{
public:
	SUV()
		:Car(100)
	{
		cout << "我是越野车,我的最高速度只有:" << getSpeed() << "km/h" << endl;
	}
};

//子类-跑车
class coupe : public Car
{
public:
	coupe()
		:Car(200)
	{
		cout << "我是跑车,我的最高速度可以到:" << getSpeed() << "km/h" << endl;
	}
};

int main()
{
	SUV s;
	coupe c;
	return 0;
}

结果

可以看到,两个子类都能具备父类中的 公有 / 保护 属性,并且能做到互不干扰

1.3、实际例子

在实际开发中,继承 会经常用到(不然也不会作为 面向对象三大特性 之一了)

比较经典的例子:C++ 中的 IO 流玩的就继承,并且还是菱形继承

举例


2、继承的定义

了解完继承相关概念后,就可以开始学习使用继承了

2.1、格式

继承的格式很简单,格式为 子类 : 继承方式 父类,比如 class a : public b 就表示 a 继承了 b,并且还是 公有继承

图解
注:Java 中的继承符号为 extern,而 C++ 中为 :

2.2、权限

继承有权限的概念,分别为:公有继承(public)、保护继承(protected)、私有继承(private

没错,与 中的访问 限定修饰符 一样,不过这些符号在这里表示 继承权限

简单回顾下各种限定符的用途

  • 公有 public:公开的,任何人都可以访问
  • 保护 protected:保护的,只有当前类和子类可以访问
  • 私有 private:私有的,只允许当前类进行访问

权限大小:公有 > 保护 > 私有
保护 protected 比较特殊,只有在 继承 中才能体现它的价值,否则与 私有 作用一样

图解

访问权限:三种
继承权限:三种

根据排列组合,可以列出以下多种搭配方案(子类的可访问情况):

访问权限 / 继承权限publicprotectedprivate
父类的 public 成员可见,变为 public可见,变为 protected可见,变为 private
父类的 protected 成员可见,变为 public可见,变为 protected可见,变为 private
父类的 private 成员不可见不可见不可见

总结:无论是哪种继承方式,父类中的私有成员始终不可被访问;当子类成员可访问父类成员时,最终权限将会变为 访问权限与继承权限 中的较小者

两种不同的权限相遇时,若可见,则在子类中变为较小者

如何证明?

继承

关于默认继承权限

  • 假设不注明继承权限,class 默认为 privatestruct 默认为 public,最好是注明继承权限

如何强行访问父类中的私有成员?

  • 在父类中设计相应的函数,获取私有成员的值进行间接访问即可

其实 C++ 中搞这么多种情况(9种)完全没必要,实际使用中,最常见到的组合为 public : publicprotected : public

2.3、使用

如何优雅的使用好 权限?

对于只想自己类中查看的成员,设为 private,对于想共享给子类使用的成员,设为 protected,其他成员都可以设为 public

比如在张三家中,张三家的房子面积允许公开,家庭存款只限家庭成员共享,而个人隐私数据则可以设为私有

class Home
{
public:
	int area = 500;	//500 平米的大房子
};

class Father : public Home
{
protected:
	int money = 50000;	//存款五万
private:
	int privateMoney = 100;	//私房钱,怎能公开?
};

class Zhangsan : public Father
{
public:
	Zhangsan()
	{
		cout << "我是张三" << endl;
		cout << "我知道我家房子有 " << area << " 平方米" << endl;
		cout << "我也知道我家存款有 " << money << endl;
		cout << "但我不知道我爸爸的私房钱有多少" << endl;
	}
};

class Xiaoming
{
public:
	Xiaoming()
	{
		cout << "我是小明" << endl;
		cout << "我只知道张三家房子有 " << Home().area << " 平方米" << endl;
		cout << "其他情况我一概不知" << endl;
	}
};

int main()
{
	Zhangsan z;
	cout << "================" << endl;
	Xiaoming x;
	return 0;
}

结果

实际使用中,权限 可以很好的保护成员


3、继承的作用域

子类虽然继承自父类,但两者的作用域是不相同的,假设出现同名函数时,默认会将父类的同名函数隐藏调,进而执行子类的同名函数

隐藏 也叫 重定义,与它类似的概念还有:重写(覆盖)、重载

3.1、隐藏

子类中出现父类的 同名 方法或成员

//父类
class Base
{
public:
	void func() { cout << "Base val: " << val << endl; }
protected:
	int val = 123;
};

//子类
class Derived : public Base
{
public:
	int func() 
	{ 
		cout << "Derived val: " << val << endl;
		return 0;
	}
private:
	int val = 668;
};

int main()
{
	Derived d;
	d.func();
	return 0;
}

结果
此时 父子类中的方法和成员均被隐藏,执行的是 子类方法,输出的是子类成员

只修改子类方法名为 funA

int funA() 
{ 
	cout << "Derived val: " << val << endl;
	return 0;
}

结果
发现此时 隐藏 消失,并且结果的是 父类方法 + 父类成员

只修改子类成员为 num

int num = 668;

结果
此时 隐藏 也消失,执行结果 子类方法 + 父类成员

综上所述,当子类中的方法出现 隐藏 行为时,优先执行 子类 中的方法;当子类中的成员出现 隐藏 行为时,优先选择当前作用域中的成员(局部优先)

这已经证明了 父子类中的作用域是独立存在的

如何显式的使用父类的方法或成员?

  • 利用域作用限定符 :: 进行访问范围的限制

解决

注意:

  • 只要是命名相同,都构成 隐藏 ,与 返回值、参数 无关
  • 隐藏会干扰调用者的意图,因此在继承中,要尽量避免同名函数的出现

4、基类与派生类对象的赋值转换

在继承中,允许将 子类 对象直接赋值给 父类,但不允许 父类 对象赋值给 子类

  • 这其实很好理解,儿子以后可以当父亲,父亲还可以当儿子吗?

并且这种 赋值 是非常自然的,编译器直接处理,不需要调用 赋值重载 等函数

//父类
class Base
{
protected:
	int val = 123;
};

//子类
class Derived : public Base
{
private:
	int num = 668;
};

int main()
{
	Base b;
	Derived d;
	b = d;
	d = b;	//非法,只允许 子->父
	return 0;
}

子类对象赋值父类对象 时,触发 切片 机制,丝滑的完成 赋值

黄瓜切片变成 黄瓜片,黄瓜片可变不回完整的黄瓜了
切片

4.1、切片

父类对象 看作一个结构体,子类对象 看作结构体Plus 版

子类对象 中多余的部分去除,留下 父类对象 可接收的成员,最后再将 对象 的指向进行改变就完成了 切片
图解
图解
因为整个切片过程是由编译器自己完成的,所以效率很高,并且不会发生 借助临时对象构造再赋值 的情况,具体切片实现原理还后续再进行讲解

注意: 切片只在 子类->父类 时发生,因为父类无法满足子类的需求


5、派生类的中的默认成员函数

派生类(子类)也是 ,同样会生成 六个默认成员函数(用户未定义的情况下)

不同于单一的 子类 是在 父类 的基础之上创建的,因此它在进行相关操作时,需要为 父类 进行考虑

图解

5.1、隐式调用

子类在继承父类后,构建子类对象时 会自动调用父类的 默认构造函数,子类对象销毁前,还会自动调用父类的 析构函数

class Person
{
public:
	Person() { cout << "Person()" << endl; }
	~Person() { cout << "~Person()" << endl; }
};

class Student : public Person
{
public:
	Student() { cout << "Student()" << endl; }
	~Student() { cout << "~Student()" << endl; }
};

int main()
{
	Student s;
	return 0;
}

结果

注意: 自动调用是由编译器完成的,前提是父类存在对应的默认成员函数;如果不存在,会报错

结果

5.2、显式调用

因为存在 隐藏 的现象,当父子类中的函数重名时,子类无法再自动调用父类的默认成员函数,此时会引发 浅拷贝 相关问题

class Person
{
public:
	Person() { cout << "Person()" << endl; }
	void operator=(const Person& P) { cout << "Person::operator=()" << endl; }
	~Person() { cout << "~Person()" << endl; }
};

class Student : public Person
{
public:
	Student() { cout << "Student()" << endl; }
	void operator=(const Student&) { cout << "Student::operator=()" << endl; }
	~Student() { cout << "~Student()" << endl; }
};

int main()
{
	Student s1;
	cout << "================" << endl;
	Student s2;
	s1 = s2;
	return 0;
}

结果

此时可用通过 域作用限定符 :: 显式调用父类中的函数

图解

总的来说,子类中的默认成员函数调用规则可以概况为以下几点:

  1. 子类的构造函数必须调用父类的构造函数,初始化属于父类的那一部分内容;如果没有默认构造函数,则需要显式调用
  2. 子类的拷贝构造、赋值重载函数必须要显式调用父类的,否则会造成重复析构问题
  3. 父类的析构函数在子类对象销毁后,会自动调用,然后销毁父类的那一部分

注意:

  • 子类对象初始化前,必须先初始化父类那一部分
  • *子类对象销毁后,必须销毁父类那一部分
  • 不能显式的调用父类的析构函数(因为这不符合栈区的规则),父子类析构函数为同名函数 destructor,构成隐藏,如果想要满足我们的析构需求,就需要将其变为虚函数,构成重写

析构函数必须设为 虚函数,这是一个高频面试题,同时也是 多态 中的相关知识


6、继承与友元函数

友元关系不能被继承

场景:友元函数 Print 可以访问父类中的私有成员,但子类继承父类后,友元函数无法访问子类中的私有成员

class Base
{
	friend void Print();
private:
	static const int a = 10;
};

class Derived : public Base
{
private:
	static const int b = 20;
};

void Print()
{
	cout << Base::a << endl;
	cout << Derived::b << endl;
}

int main()
{
	Print();
	return 0;
}

结果

如果想让 Print 函数也能访问子类中的私有成员,则需要 将其也声明为子类的友元函数

结果
总之记住:友元关系不能被继承

这个就像是西欧社会中的一句名言:我的附庸的附庸,不是我的附庸

结果


7、继承与静态成员

静态成员是唯一存在的,无论是否被继承

静态变量为于静态区,不同于普通的堆栈区,静态变量的声明周期很长,通常是程序运行结束后才会被销毁,因此 假设父类中存在一个静态变量,那么子类在继承后,可以共享此变量

可以利用这个特性,写一个统计 创建多少个父类子类对象 的小 demo

class Base
{
	friend void Print();
public:
	Base() { num++; }
	static int num;	//静态变量
};

int Base::num = 0;	//初始化静态变量

class Derived : public Base
{
public:
	Derived() { num++; }
};

void Print()
{
	cout << Base::num << endl;
}

int main()
{
	Derived d1;
	Derived d2;
	Derived d3;
	Print();
	return 0;
}

结果
创建了三个子类对象,同时 因为在创建子类对象前,会自动调用父类的默认构造函数,因此最终结果为 6

这也从侧面证明了静态成员是唯一存在的,并且被子类共享


8、菱形继承

单继承:一个子类只能继承一个父类
多继承:一个子类可以继承多个父类(两个及以上)

C++ 支持多继承,即支持一个子类继承多个父类,使其基础信息更为丰富,但凡事都有双面性,多继承 在带来巨大便捷性的同时,也带来了个巨大的坑:菱形继承问题

注:其他面向对象的高级语言为了避免出现此问题,直接规定了不允许出现多继承

菱形

8.1、概念

首先 C++ 允许出现多继承的情况,如下图所示

图解
这样看很正常是吧,但如果出现以下这种 重复继承 的情况,就比较麻烦了

图解

此时 普通人X 会纠结于使用哪一个 不用吃饭 的属性!这对于编译器来说,是一件无法处理的事

8.2、现象

将上述概念转化为代码,观察实际现象

注:多继承时,只需要在 父类 之后,添加 , 号,继续增加想要继承的父类

class Person
{
public:
	string _name;	//姓名
};

//本科生
class Undergraduate : public Person
{};

//研究生
class Postgraduate : public Person
{};

//毕业生
class Graduate : public Undergraduate, public Postgraduate
{};

int main()
{
	Graduate g1;
	g1._name = "zhangsan";

	return 0;
}

无法编译!

结果

8.3、原因

Undergraduate 中继承了 Person_namePostgraduate 也继承了 Person_name

Graduate 多继承 Undergraduate Postgraduate 后,同时拥有了两个 _name,使用时,无法区分!

图解

通过监视窗口查看信息:

图解

8.4、解决方法

想要解决二义性很简单,通过 :: 限制访问域即可

Graduate g1;
g1.Undergraduate::_name = "zhangsan";
cout << g1.Undergraduate::_name << endl;

结果

但这没有从本质上解决问题!而且还没有解决数据冗余问题

真正的解决方法:虚继承

注:虚继承是专门用来解决 菱形继承 问题的,与多态中的虚函数没有直接关系

虚继承:在菱形继承的腰部继承父类时,加上 virtual 关键字修饰被继承的父类

class Person
{
public:
	string _name;	//姓名
};

//本科生
class Undergraduate : virtual public Person
{};

//研究生
class Postgraduate : virtual public Person
{};

//毕业生
class Graduate : public Undergraduate, public Postgraduate
{};

int main()
{
	Graduate g1;
	g1._name = "zhangsan";
	cout << g1._name << endl;

	return 0;
}

此时可以解决 菱形继承数据冗余二义性 问题

图解

虚继承是如何解决菱形继承问题的?

  • 利用 虚基表 将冗余的数据存储起来,此时冗余的数据合并为一份
  • 原来存储 冗余数据 的位置,现在用来存储 虚基表指针

图解

此时无论这个 冗余 的数据存储在何处,都能通过 基地址 + 偏移量 的方式进行访问

虚继承相关知识补充

虚继承底层是如何解决菱形继承问题的?

  • 对于冗余的数据位,改存指针,该指针指向相对距离
  • 对于冗余的成员,合并为一个,放置后面,假设想使用公共的成员(冗余成员),可以通过相对距离(偏移量)进行访问
  • 这样就解决了数据冗余和二义性问题

为何在冗余处存指针?

  • 指针指向空间有预留一个位置,可以用于多态
  • 因此虚继承用的是第二个位置

新建对象进行兼容赋值时,对象指向指针处

  • 该指针(偏移量)指向的目标位置不定
  • 无论最终位置在何处,最终汇编指令都一样(得益于偏移量的设计模式)

虚函数是否会造成空间浪费?

  • 不会,指针大小固定为 4/8 字节

指针所指向的空间(虚基表)是否浪费空间?

  • 可以忽略不计,所有对象共享

假设存在多个共享成员,需要新增指针(偏移量),因为这些成员都是连续的,找到第一个,即可找到其他

  • 即使涉及内存对齐问题,编译器也会根据规则做出调整

为了解决 菱形继承 问题,想出了 虚继承 这种绝妙设计,但在实际使用中,要尽量避免出现 菱形继承 问题


9、补充

继承是面向对象三大特性之一,非常重要,需要对各种特性进行学习

关于多继承时,哪个父类先被初始化的问题

  • 谁先被声明,谁就会先被初始化,与继承顺序无关

除了可以通过继承使用父类中的成员外,还可以通过 组合 的方式进行使用

  • 公有继承:is-a —> 高耦合,可以直接使用父类成员
  • 组合:has-a —> 低耦合,可以间接使用父类成员

实际项目中,更推荐使用 组合 的方式,这样可以做到 解耦,避免因父类的改动而直接影响到子类

当然,使用哪种方式还要取决于具体场景,具体问题具体分析

//父类
class A {};

//继承
class B : public A
{
    //直接继承,直接使用
};

//组合
class C
{
private:
    A _aa;  //创建 A 对象,使用成员及方法
}

可能有的人问 继承 到底有什么用?答案很简单,为后面的 多态 实现铺路,也就是说,多态的实现离不开继承!

关于之前的 适配器 模式,除了可以使用 组合 的方式进行适配外,还可以通过 继承 的方式进行适配

  • queue -> dequelist
  • reverse_iterator -> iterator

在通过后者实现前者时,可以通过 组合,也可以通过 继承


🌆总结

以上就是本次关于 C++【继承】的全部内容了,在本篇文章中,我们重点介绍了继承的相关知识,如什么是继承、如何继承、继承该注意些什么,最后还学习了多继承模式中容易引发的菱形继承问题,探究了其原因及解决方法,关于继承是如何辅助实现多态的,可以期待下篇文章:C++【多态】


星辰大海

相关文章推荐

STL 之 泛型思想

C++【模板进阶】

C++【模板初阶】

STL 之 适配器

C++ STL学习之【优先级队列】

C++ STL学习之【反向迭代器】

C++ STL学习之【容器适配器】

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

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

相关文章

linux创建新用户

只需要四步就能创建一个新的linux用户 1.打开终端 快捷键CtrlAltT 2.创建用户和密码 sudo useradd -m aaa 创建用户名为aaa的用户 -m&#xff1a;自动建立用户的登入目录 sudo是允许系统管理员让普通用户执行root命令的一个工具&#xff08;获取权限&#xff09; 这里会需要输…

Packet Tracer安装包及安装教程(8.0版本)

Packet Tracer安装包下载链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/19BbCZzSxukKKdsdaqw7dHw 提取码&#xff1a;6666 &#xff08;若果链接失效&#xff0c;可在评论区留言。&#xff09; 安装步骤 1、解压缩文件&#xff0c;得到 cisco packet tr…

[架构之路-198] - 功能需求与分析:1张图、 4个阶段、16个步骤,系统分析问题与彻底解决问题的方法:问题界定、原因分析、方案确认、落实执行

目录 前言&#xff1a;一张图&#xff1a; 一、界定问题&#xff1a;找到真正的问题&#xff0c;问题就解决了一大半 1.发现异常&#xff1a; 2.优先顺序&#xff1a; 3.描述现状&#xff1a; 4.确定目标&#xff1a; 二、要因分析&#xff1a;透过表象&#xff0c;直达…

Synopsys的仿真软件Hspice 2022版在Windows系统上的下载安装教程

目录 前言一、Hspice安装二、安装许可管理工具三、配置使用总结 前言 Synopsys HSPICE是电子电路仿真领域非常强大的软件&#xff0c;具有模拟和分析MOS元件的算法。HSPICE用于分析基本的电子电路&#xff0c;如晶体管&#xff0c;不包括电子元件&#xff0c;如微控制器。该软…

虚拟机搭建宝蓝德中间件(三)

2.1. 准备介质 2.1.1. 介质包&#xff1a; 宝兰德中间件的介质名为&#xff1a;BES-9.5.2.4703.tar.gz&#xff0c;该介质包适用于不同操作系统和 硬件平台。 2.1.2. 上传 BES952 单机版介质&#xff0c;上传路径&#xff1a;/home/bes 2.1.3. 新建 BES 中间件目录&#xff0c;…

基于阿里云物联网平台的Android物联网软件框架

Android 物联网APP 提示&#xff1a;该工程是连接阿里云物联网平台的模板代码&#xff0c;将MQTT连接、JSON数据的订阅发布等操作封装&#xff0c;并且能够迅速将获取到的数据显示到手机界面上。使用了Servier进行网络连接的逻辑操作&#xff0c;并且使用自定义控件&#xff0…

uni-app嵌入微信小程序原生代码

使用uni-app有时需要用到微信小程序原生代码 解析: uni-app项目结构跟原生小程序的项目结构有着不一致的区别,如果说开发过程中必须要使用原生代码,就需要把原生代码作为组件的方式在uni-app项目中引入使用官网为了应对这一个需求,就给出了以下方法,供开发者实现 wxcomponent…

SQL注入详解(全网最全,万字长文)

漏洞原因 一些概念&#xff1a; SQL&#xff1a;用于数据库中的标准数据查询语言。 web分为前端和后端&#xff0c;前端负责进行展示&#xff0c;后端负责处理来自前端的请求并提供前端展示的资源。 而数据库就是存储资源的地方。 而服务器获取数据的方法就是使用SQL语句进…

Android Studio App开发中数据库SQLite的解析及实战使用(包括创建数据库,增删改查,记住密码等 附源码必看)

运行有问题或需要源码请点赞关注收藏后评论区留言~~~ SQLite简介 SQLite是一种小巧的嵌入式数据库&#xff0c;使用方便&#xff0c;开发简单&#xff0c;如同mysql&#xff0c;oracle那样&#xff0c;SQLite也采用SQL语句管理数据&#xff0c;由于它属于轻型数据库&#xff0…

【网络】- TCP/IP四层(五层)协议 - 数据链路层

一、概述 TCP/IP 在最初定义时&#xff0c;是一个四层的体系结构&#xff0c;包括应用层、传输层、网络层、网络接口层。由于最下面的网络接口层并没有什么具有内容。因此&#xff0c;在学习计算机网络原理时&#xff0c;往往采用折中的办法&#xff0c;综合了 OSI 和 TCP/IP 的…

数据结构与算法----详解二叉树的遍历(迭代、递归)

文章目录 实现二叉树的类前序遍历中序遍历后序遍历层次遍历总结 ❤️ 作者简介&#xff1a;大家好我是小鱼干儿♛是一个热爱编程、热爱算法的大三学生&#xff0c;蓝桥杯国赛二等奖获得者&#x1f41f; 个人主页 &#xff1a;https://blog.csdn.net/qq_52007481⭐ 个人社区&…

微信小程序跳转微信内置浏览器

最近遇到一个需求&#xff0c;需要微信小程序跳转到微信内置浏览器&#xff0c;但是官网并没有给出相关文档。查阅了大量资料&#xff0c;发现有两种实现方式。 1、通过微信公众号文章实现 小程序可以使用web-view打开关联的公众号文章&#xff0c;公众号文章可以在阅读全文放…

macOS Ventura 13.3 (22E252) 正式版 ISO、DMG镜像下载

macOS Ventura 版本历史 Release: macOS Ventura 13.3 (22E252), 2023-03-27macOS Ventura 13.2.1 (22D68), 2023-02-18macOS Ventura 13.2 (22D49), 2023-01-23macOS Ventura 13.1 (22C65), 2022-11-13macOS Ventura 13.0.1 (22A400), 2022-11-09macOS Ventura 13.0 (22A380…

关于结构体初始化的自我小结

前段时间在一个项目中使用到结构体数组来存储产品不同型号的参数&#xff0c;使程序通用化&#xff0c;便于测试和快速生产。由于之前很少使用结构体数组&#xff0c;在初始化时遇到了一点小阻碍&#xff0c;于是便想到对于结构体和其数组的初始化操作做一个小总结&#xff1a;…

前端笔试常考设计模式,操作系统,数据结构,ACM模板,经典算法,正则表达式,常用方法

考试时允许使用草稿纸&#xff0c;请提前准备纸笔。考试过程中允许上厕所等短暂离开&#xff0c;但请控制离开时间 笔试得分60%一般通过&#xff0c;面试答对80%才能通过 合集&#xff1a;2023年最全前端面试题考点HTML5CSS3JSVue3React18八股文手写项目笔试_参宿7的博客-CSD…

Microsoft Visual Studio 2019正式版离线安装包下载

原文地址&#xff1a;https://www.bitecho.net/microsoft-visual-studio-2019.html#respond Visual Studio&#xff08;简称VS&#xff09;是微软公司的开发工具包系列产品&#xff0c;包括了整个软件生命周期中所需要的大部分工具&#xff0c;如UML工具、代码管控工具、集成开…

DIY信号发生器:运放实现三角波、方波发生器(详细参数说明)+multisim仿真

前言 信号发生器是电子工程师最常用的几个仪器之一吧&#xff0c;三角波和方波是最常用的波形&#xff0c;在之前的文章中&#xff0c;我们已经介绍过RC延迟电路&#xff0c;今天我就教大家通过RC延迟和运放来实现三角波和方波。 仿真软件版本 本次介绍的电路是通过multisim…

kafka如何保证消息不丢失?半分钟的答案和半个小时的答案有点不一样。

文章目录 一、Kafka在哪些场景下有丢消息的可能&#xff1f;二、面试流经典答法三、为什么金融场景没人会用Kafka&#xff1f;总结 ​ kafka如何保证消息不丢失&#xff1f; 这是面试最常问到的问题。但是其实这是一个最体现综合实力的开放性题目。把这问题真正弄明白&#xf…

uni - app

uni-app 使用vue的语法&#xff0c;vue指令 小程序的标签和 API <template><view class"content"><image class"logo" src"/static/logo.png"></image><view class"text-area"><text class"t…

期末作业C#实现学生宿舍管理系统

??开发背景 完整代码下载地址&#xff1a;点我下载 优化移步&#xff1a; 《c#中在datagridview的表格动态增加一个按钮方法》 《C#实现多窗口切换&#xff1a;Panel详细教程&#xff08;亲测&#xff09;》 文章还在更新&#xff0c;上次更新时间2022/06/20 20:49 由于快期…