C++继承

文章目录

  • 继承的概念和定义
    • 继承的概念
    • 继承定义
      • 继承定义格式
      • 继承基类成员访问方式的变化
  • 基类和派生类对象赋值转换
  • 继承中的作用域
  • 派生类的默认成员函数
  • 继承与友元
  • 继承与静态成员
  • 复杂的菱形继承及菱形虚拟继承
    • 菱形虚拟继承
    • 菱形虚拟继承原理
      • 菱形虚拟继承中虚指针应用
  • 继承的总结和反思
    • 继承与组合

继承的概念和定义

继承的概念

1: 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序:员在保持原有类特性的基础上进行扩展,增加功能,这样产生的类,称为派生类。
2: 继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承为是类设计层次的复用。

继承定义

继承定义格式

在这里插入图片描述

class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	string _name = "perter";
	int  _age = 18;
};
//继承后父类的Person成员(成员函数+成员变量)都会成为子类的一部分,这里体现出Stuident复用Person的成员。
class Student :protected Person
{
public:
	void Print()
	{
		cout << _name << endl;
	}
protected:
	int _stuid;
	int _major;
};

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

基类中被不同访问限定符修饰的成员(成员变量,成员函数),当以不同的继承方式继承时,该成员的最终访问方式也会变化。
变化方式如图
在这里插入图片描述
总结
在基类和派生类继承关系中:
如图,我们可以认为三种访问限定符的权限大小为:

public > protected > private;

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

注意;
如果基类A的公有成员以private的方式继承,此时该公有成员在派生类B的继承方式变为派生类的private成员,此时派生类B可以在派生类中对该成员进行访问,但是如果有一个派生类C继承了B,那么此时B就对于C而言变成了基类,基类的private成员在派生类C中都是不可见的。所以,继承过后成员变量的访问权限改变影响的是下一次继承。

2: 使用关键字时class 的默认继承方式为private, 使用struct 时默认继承方式为public,不过我们最好显示的写出继承关系。

3: 基类的私有成员在派生类中都是不可见的(无论以什么方式继承),基类中的其他成员在派生类中的访问方式== Min( 成员在基类中的访问限定符和继承方式权限最小的)该访问方式影响的是下一个派生类。

4:基类中的private成员在派生类中不可以访问,protected成员在派生类中可以访问。对于类内外来说,都不可以访问。

class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	string _name = "perter";
	int  _age = 18;
};
//private继承,此时基类在派生类的访问方式变为private,该访问权限改变影响着下一次继承。此时依旧可以访问基类中的protected成员。
class Student : private  Person
{
public:
	void Print() 
	{
		cout << _name << endl;
		cout << _age << endl;
	}
protected:
	int _stuid;
};
//Student的成员访问方式为private,Student1派生类中不可以访问Student中的private成员的。
class Student1 : public Student
{
public:
	void Print1()
	{
		cout << _name << endl;  //
		cout << _age << endl;
	}
};

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

1: 派生类对象可以赋值给 基类的对象/ 基类的指针 / 基类的引用

2: 基类对象不能赋值给派生类。

class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
public:
	string _name = "perter";
	int  _age = 18;
};
class Student : public  Person
{
public:
	void Print()
	{
		cout << _name << endl;
		cout << _age << endl;
	}
protected:
	int _stuid;
};


int main()
{
	Person p;
	Student s;
	Person&  p1 = s;   //派生类对象赋值给基类对象
	Person* p2 = &s;   //派生类对象赋值给基类指针
	Person& p3 = s;    //派生类对象赋值给基类引用
	s = p;             //基类对象不能赋值给派生类对象
}
	

例如
派生类对象赋值给基类对象
又叫切割,将派生类中基类的那一部分赋值。
在这里插入图片描述
派生类对象赋值给基类指针:
p指向的内容为Student派生类中基类的那一部分。
在这里插入图片描述

派生类对象赋值给基类的引用:
取子类中父类的的那一部分引用。
在这里插入图片描述

继承中的作用域

1: 在继承体系中基类和派生类都有独立的作用域。

2: 基类和派生类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,编译器优先从最近的作用域寻找,这种情况叫做隐藏。,也叫重定义。所以如果在子类成员函数中访问基类成员,可以是使用 基类::基类成员 显示访问。

3:对于基类和派生类来说,只要函数满足函数名相同就构成隐藏。

注意
隐藏是对于基类和派生类两个作用域而言的,只要函数成员满足函数名相同就构成隐藏,而函数重载对于同一个作用域而言,并且对形参类型,个数,返回值也有限制。

class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
public:
	string _name = "perter";
	int  _age = 18;
	int _stuid = 1;
};
class Student : public  Person
{
public:
	void Print(int a = 0,int b = 1)
	{
		cout << _name << endl;            
		cout << _age << endl;
		cout << _stuid << endl;            //11
		cout << Person::_stuid <<endl;     // 1
		Person::Print();                  //peter, 18
	}

protected:
	int _stuid = 11;
};

int main()
{
	Student s;
	s.Print();
}

派生类的默认成员函数

派生类中6个默认成员函数:
在这里插入图片描述

class Person
{
public:
//基类构造
	Person(const string& 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)
	{
		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)
	{
	}
//赋值
	Student& operator=(const Student& s)
	{
		if (this != &s)
		{
			Person::operator=(s);
			_num = s._num;
		}
		return *this;
	}
//析构
	~Student()
	{
		cout << "~Student" << endl;
		//
		Person::~Person();

	}
protected:
	int _num;
};
int main()
{
	Student s("ppp", 1);   //调用构造函数.
	Student s1 = s;        //调用拷贝构造
	
	Student s2("yzh", 2);   
	s2 = s1;               //调用赋值.
	return 0;
}

注意:
拷贝构造:
我们已知基类拷贝构造形参为Person& p,所以在子类调用时很难从子类中拿到父类对象传参,但是我们可以传子类对象,引用的为子类对象中父类的那一部分,也叫做切片.
赋值:
在调用基类赋值时一定要标明作用域,因为基类赋值和派生类赋值同名,为隐藏关系,如果不标明,编译器会默认调用自身赋值,这样就会无限循环.
析构
1:由于多态的处理,派生类的析构和基类的析构会被统一处理为destructtor(),此时它们互为隐藏关系,所以在调用基类析构时需要标明作用域.
2: 由于函数栈帧先进后出原则,创建一个派生类的对象时先构造基类再构造派生类,所以根据先构造的后析构原则,编译器在派生类析构函数后面会主动调用基类析构.这样才能保证先析构派生类后析构基类.而自己显示写无法保证先析构派生类后析构基类.

继承与友元

友元关系不能继承,也就是说基类的友元函数可以访问基类的私有和保护成员,但是不能访问派生类的私有和保护成员.
比如:
Display函数时基类Person的友元,Display希望能够访问基类和派生类的私有和保护成员,但是Display函数并不是派生类Student的友元,即Display函数无法访问派生类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;
	Display(p, s);
	return 0;
}

解决办法:
如果我们也想让Display友元函数也能够访问派生类Student的私有和保护成员,可以在派生类中添加友元函数声明.

class Student : public Person
{

	friend void Display(const Person& p, const Student& s);
protected:
	int _stuNum; //学号
};

继承与静态成员

如果基类中定义了static静态成员,说明这个静态成员只在静态区,无论派生出多少个子类,都只有一个static成员实例.

using namespace std;
//基类
class Person
{
public:
	Person()
	{
		_count++;
	}
protected:
	string _name; //姓名
public:
	static int _count; //统计人的个数。
};
//类外定义,类型,名字,初始值.
//静态成员类外初始化.
int Person::_count = 0; 
//派生类
class Student : public Person
{
protected:
	int _stuNum; //学号
};
//派生类
class Graduate : public Person
{
protected:
	string _seminarCourse; //研究科目
};
int main()
{
	Person p;
	Student s;
	++Person::_count;
	cout << Student::_count << endl;  //3
	cout << Student::_count << endl;  //3
	//打印的地址也相等.
	cout << &Person::_count << endl;//00007FF76B093444
	cout << &Student::_count << endl;
	//00007FF76B093444
	return 0;
}

复杂的菱形继承及菱形虚拟继承

单继承:
一个子类只有一个直接父类时称这个继承关系为单继承.
在这里插入图片描述
多继承:
一个子类有两个或两个以上直接父类时称这个继承关系为多继承.
在这里插入图片描述
菱形继承:
菱形继承是多继承中的一种特殊情况…
在这里插入图片描述

从下面的成员构造可以看出,菱形继承有数据冗余和二义性问题.
数据冗余:
Assistant的对象的Person成员会存在两份.
在这里插入图片描述

using namespace std;
//基类
class Person
{
public:
	string _name; //姓名
};
class Student : public Person
{
protected:
	int _stuNum; //学号
};
class Teacher : public Person
{
protected:
	int _id;
};
class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse;
};
int main()
{
	Assistant a;
	//菱形继承的二义性问题,对访问哪个_a不明确.
	a._name = "yzh"; 
}


** 二义性解决办法**:
因为Assistant对象继承的基类为Student和Teacher,但是Student和Teacher都继承了基类Person.所以当访问Assistant对象中的_name成员会出现访问不明确.
所以当菱形继承时,在访问Assistant对象中的_name时我们可以指定Assistant继承基类的类域,希望访问哪个类域的_name就指定哪个.

int main()
{
	Assistant a;
	//菱形继承的二义性问题,对访问哪个_a不明确.
	a._name = "yzh"; 
	
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";
}

但是,仍然不能解决数据冗余的问题,此时便要用到菱形虚拟继承.

菱形虚拟继承

菱形虚拟继承可以解决菱形继承中的二义性读和数据冗余问题.


1:此时,我们便可以直接访问Assisstant对象中的成员_name了,并且我们指定访问Assistant中的Student基类和Teacher基类中的_name都是同一个结果,这便解决了二义性问题.
2:并且当我们打印Assistant对象中Student基类和Teacher基类中的_name时,也是同一个地址.这便解决了数据冗余问题.

菱形虚拟继承原理

例如:

class A
{
public:
	int _a;
};
// class B : public A
class B :  public A
{
public:
	int _b;
};
// class C : public A
class C :  public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

现在,我们来看看菱形继承时,借助内存窗口观察对象成员的模型.
在这里插入图片描述
也就是说,D类对象当中的成员分布如下:
D类对象中有两个类A的成员,这也就菱形继承导致数据冗余和二义性的原因.
在这里插入图片描述

现在,我们从内存窗口中看看菱形虚拟继承各窗口分布情况.

class A
{
public:
	int _a;
};
class B : virtual public A
{
public:
	int _b;
};
class C : virtual public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._c = 4;
	d._b = 3;
	d._d = 5;
	return 0;
}

在这里插入图片描述
也就是对象D中菱形虚拟继承的内存分布如下:
1:D中B里面继承了A,D中C里面继承了A,他们的排布按照函数栈帧由低到高进行分布,分别为先B中的成员由低到高到C中的成员进行分布,最后再为D.
2: 将B,C中的_a成员变为了两个指针,这两个指针中第一个位置预留的值为零,第二个位置存的是偏移量(距离公共成员_a的距离.如果我们要从类B中访问到公共内置成员_a,必须通过B中指针的偏移量去访问到公共内置成员_a.
在这里插入图片描述

菱形虚拟继承中虚指针应用

测试代码如下:

class A
{
public:
	int _a;
};
class B :  public A
{
public:
	int _b;
};
class C : public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
void Func( B* ptr )
{
	cout << ptr->_a << endl;
}
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._c = 4;
	d._b = 3;
	d._d = 5;
	B* pb = &d;
	Func(pb);
	return 0;
}

1:对于函数Func()来说,如果传的是类B对象的地址,那么就是正常调用,可是,如果传的是派生类对象的地址,那么此时便会发生继承中的赋值转换,那么此时ptr指向内容为派生类对象中与基类共有的部分.所以,如果虚基类没有统一模型,进而虚指针来寻找虚表的话,此时ptr根本不知道公共成员_a的位置.
2: 如果虚基类中有多个内置成员也不需要添加多个虚指针,此时只要通过虚指针继续添加偏移量就可以找到其他内置成员的.

继承的总结和反思

继承与组合

is-a关系:
继承是一种is-a的关系,也就是说每个派生类对象都是一个基类对象.
例如:
人<——学生, 植物<——玫瑰花,车类<——宝马类

class Car
{
protected:
	string _colour; 
	string _num; 
};
class BMW : public Car
{
public:
	void Drive()
	{
		cout << "this is BMW" << endl;
	}
};

has-a关系:
has-a是一种组合关系,就是一个对象中包含了另外一个对象.
例如:
轮胎和车

class Tire
{
protected:
	string _brand; //品牌
	size_t _size; //尺寸
};
class Car
{
protected:
	string _colour; //颜色
	string _num; //车牌号
	Tire _t; //轮胎
};

注意:
继承和组合关键点在于访问权限不同.
如果是组合关系,那么Tire中protected内置成员就无法在Car直接访问,
如果是继承关系,那么Tire中的protected内置成员就可以在Car直接访问.

class Tire
{
protected:
	string _brand; 
	int _size =1; 
};
class Car
{
public:
	string _colour; 
	string _num;
	Tire _t;
public:
	void Func()
	{
		cout << _t._size << endl; //不可以访问.
	}
};
int main()
{
	Car c;
}

总结:
1:继承允许你根据基类的实现来定义派生类的实现,这种通过生成派生类的复用通常被称为白箱复用(White-boxreuse).术语“白箱”是相对可视性而言:在继承方式中,基类的内部细节对于派生类可见,继承一定程度破坏了基类的封装,基类的改变对派生类有很大的影响,派生类和基类间的依赖性关系很强,耦合度高。
2:组合是类继承之外的另一种复用选择,新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口,这种复用风格被称之为黑箱复用(Black-box reuse),因为对象的内部细节是不可见的,对象只以“黑箱”的形式出现,组合类之间没有很强的依赖关系,耦合度低,优先使用对象组合有助于你保持每个类被封装,组合中我们可以通过被组合对象的接口进行访问来访问被组合对象成员
3:实际中我们应该尽量使用组合,组合的耦合度低,如果类与类之间的关系既符合继承也符合组合,那么优先选择组合.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】字符串函数和内存函数

前言&#x1f338;在我们编写C程序时&#xff0c;除了使用自定义函数&#xff0c;往往还会使用一些库函数&#xff0c;例如标准输入输出函数printf&#xff0c;scanf&#xff0c;字符串函数strlen&#xff0c;内存函数memset等等&#xff0c;使用这些系统自带的库函数可以轻松地…

MongoDB【部署 01】mongodb最新版本6.0.5安装部署配置使用及mongodb-shell1.8.0安装使用(云盘分享安装文件)

云盘分享文件&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/11sbj1QgogYHPM4udwoB1rA 提取码&#xff1a;l2wz 1.mongodb简单介绍 MongoDB的 官网 内容还是挺丰富的。 是由 C语言编写的&#xff0c;是一个基于分布式文件存储的开源数据库系统。在高负载的情况下&…

【JavaEE初阶】第八节.网络原理网络层和数据链路层,应用层

文章目录 前言 一、网络层协议 1.1 IP协议 1.2 IP地址&#xff1b; 1.3 路由选择&#xff1b; 二、数据链路层 2.1 以太网协议&#xff1b; 三、应用层&#xff1b; 3.1 应用层协议DNS&#xff1b; 3.2 DNS是如何完成转换的&#xff1b; 3.3 如何解决DNS访问量太高的…

c语言的基础知识之结构体

目录前言结构体结构的自引用typedef函数结构体内存对齐修改默认对齐数位段什么是位段位段的内存分配位段的跨平台问题位段的意义以及应用枚举枚举常量的赋值枚举的优点总结前言 欢迎来到戴佳伟的小课堂&#xff0c;那今天我们讲啥呢&#xff1f; 问得好&#xff0c;我们今天要讲…

数据库面试题——锁

了解数据库的锁吗&#xff1f; 锁是数据库系统区别于文件系统的一个关键特性&#xff0c;锁机制用于管理对共享资源的并发访问。 InnoDB下两种标准行级锁&#xff1a; 共享锁&#xff08;S Lock&#xff09;&#xff0c;允许事务读一行数据。 排他锁&#xff08;X Lock&…

图解如何一步步连接远程服务器——基于VScode

基于VScode连接远程服务器 安装Remote-SSH等插件 想要在vscode上连接远程服务器需要下载Remote-SSH系列插件&#xff1a; 直接在插件中搜索remote&#xff0c;即可找到&#xff0c;选择图片中的3个插件&#xff0c;点击install安装。 配置Remote-SSH 在这个步骤有多种操作…

和ChatGPT对比,文心一言的表现已经是中国之光了

网络上各种测评满天飞&#xff0c;这里就不展开说了&#xff0c;针对“chatgpt”这项技术的难点&#xff0c;是十分巨大的。当你对文心一言以及其他国产AI软件存在不满的时候&#xff0c;你可以简单对着chatgpt或者文心一言搜索&#xff01;ChatGPT技术难点通俗来讲难度&#x…

节流还在用JS吗?CSS也可以实现哦

函数节流是一个我们在项目开发中常用的优化手段&#xff0c;可以有效避免函数过于频繁的执行。一般函数节流用在scroll页面滚动&#xff0c;鼠标移动等。 为什么需要节流呢&#xff0c;因为触发一次事件就会执行一次事件&#xff0c;这样就形成了大量操作dom,会出现卡顿的情况…

LeetCode:35. 搜索插入位置

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340;算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 一、&#x1f331;35. 搜索插入位置 题目描述&#xff1a;给定一个排序数组和一个目标值&…

CentOS8服务篇10:FTP服务器配置与管理

一、安装与启动FTP服务器 1、安装VSFTP服务器所需要的安装包 #yum -y install vsftpd 2、查看配置文件参数 Vim /etc/vsftpd/vsftpd.conf &#xff08;1&#xff09;是否允许匿名登录 anonymous_enableYES 该行用于控制是否允许匿名用户登录。 &#xff08;2&…

年报前瞻:文化产业高质量发展确定性,关注腾讯音乐三大关键能力

港股进入年报季&#xff0c;今年的披露期拥有比往年更多的看点。 一方面&#xff0c;经济复苏态势明显&#xff0c;线上线下消费均有回暖&#xff0c;市场已经对去年的整体表现有更多预期&#xff0c;正关注企业对后续发展的思考&#xff1b;另一方面&#xff0c;两会结束&…

2023美赛C题【分析思路+代码】

以下内容为我个人的想法与实现&#xff0c;不代表任何其他人。 文章目录问题一数据预处理时间序列模型创建预测区间单词的任何属性是否影响报告的百分比&#xff1f;如果是&#xff0c;如何影响&#xff1f;如果不是&#xff0c;为什么不是&#xff1f;问题二问题三难度评估模型…

【Vue3】利用vite创建vue3项目

&#x1f3c6;今日学习目标&#xff1a;利用vite创建vue3项目 &#x1f603;创作者&#xff1a;颜颜yan_ ✨个人格言&#xff1a;生如芥子&#xff0c;心藏须弥 ⏰本期期数&#xff1a;第二期 &#x1f389;专栏系列&#xff1a;Vue3 文章目录前言vite简介利用vite创建vue3项目…

二叉搜索树

1.基础概念介绍 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 1.若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 2.若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 3.它…

设置Typora图床(Github)

PicGo&#xff0c;Github&#xff0c;Typora Nodejs下载&#xff1a; Node.js PicGo下载&#xff1a; GitHub - Molunerfinn/PicGo: A simple & beautiful tool for pictures uploading built by vue-cli-electron-builder 选择downloads或release. 然后进行安装。 Gith…

经典PID控制算法原理以及优化思路

文章目录0、概念1、理解2、实现3、优化4、引用0、概念 PID算法是工业应用中最广泛算法之一&#xff0c;在闭环系统的控制中&#xff0c;可自动对控制系统进行准确且迅速的校正。PID控制&#xff0c;即Proportional – Integral(I) – Derivative(D) Control, 实际上是三种反馈…

Transformer到底为何这么牛

从注意力机制&#xff08;attention&#xff09;开始&#xff0c;近两年提及最多的就是Transformer了&#xff0c;那么Transformer到底是什么机制&#xff0c;凭啥这么牛&#xff1f;各个领域都能用&#xff1f;一文带你揭开Transformer的神秘面纱。 目录 1.深度学习&#xff0…

STM32外设-DMA

1. 简介 DMA(Direct Memory Access)—直接存储器存取&#xff0c;是单片机的一个外设&#xff0c;它的主要功能是用来搬数据&#xff0c;但是不需要占用 CPU&#xff0c;即在传输数据的时候&#xff0c; CPU 可以干其他的事情&#xff0c;好像是多线程一样。数据传输支持从外设…

初时STM32单片机

目录 一、单片机基本认知 二、STM系列单片机命名规则 三、标准库与HAL库区别 四、通用输入输出端口GPIO 五、推挽输出与开漏输出 六、复位和时钟控制&#xff08;RCC&#xff09; 七、时钟控制 八、中断和事件 九、定时器介绍 一、单片机基本认知 单片机和PC电脑相比…

【python进阶】你真的懂元组吗?不仅是“不可变的列表”

&#x1f4da;引言 &#x1f64b;‍♂️作者简介&#xff1a;生鱼同学&#xff0c;大数据科学与技术专业硕士在读&#x1f468;‍&#x1f393;&#xff0c;曾获得华为杯数学建模国家二等奖&#x1f3c6;&#xff0c;MathorCup 数学建模竞赛国家二等奖&#x1f3c5;&#xff0c…
最新文章