【面向对象语言三大特性之 “继承”】

news2024/11/13 12:43:07

目录

1.继承的概念及定义

1.1继承的概念

1.2 继承定义

1.2.1定义格式

 1.2.2继承关系和访问限定符

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

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

3.继承中的作用域

4.派生类的默认成员函数

5.继承与友元

6. 继承与静态成员

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

8.继承的总结和反思

9.笔试面试题


1.继承的概念及定义

1.1继承的概念

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

 我们来举个栗子:

首先我们定义一个基类Person:

class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	string _name = "peter";//  姓名
	int _age = 18;//  年龄
};

再定义两个子类Stuend和Teacher,这两个子类是继承了父类的成员(成员函数+成员变量)

我们可以通过监视窗口来查看:

 不难发现的确子类继承了父类的成员。

1.2 继承定义

1.2.1定义格式

下面我们看到Person是父类,也称作基类。Student是子类,也称作派生类。

 

 1.2.2继承关系和访问限定符

 

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

类成员 / 继承方式
public继承 protected继承 private继承
基类的 public 成员
派生类的public成员
派生类的 protected
成员
派生类的 private
成员
基类的 protected 成员
派生类的 protected
成员
派生类的 protected
成员
派生类的 private
成员
基类的 private 成员
在派生类中不可见在派生类中不可见
在派生类中不可见
总结:
  • 1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在子类里面还是子类外面都不能去访问它
  • 2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected可以看出保护成员限定符是因继承才出现的
  • 3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式)public > protected > private
  • 4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public不过最好显示的写出继承方式
  • 5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。

 这些大家可以自行去验证,这里我就不再多说了。


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

  • 派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。
  • 基类对象不能赋值给派生类对象。
  • 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(Run Time Type Information)dynamic_cast  来进行识别后进行安全转换。(ps:这个我们后面再讲解,这里先了解一下)

 看下面这样一段代码:

int main()
{
	Student sobj;
	Person pobj = sobj;
	Person* pp = &sobj;
	Person& rp = sobj;
	return 0;
}

我们发现编译既然是没有错误的,这里就将子类切片给了父类。

(注意:切片行为是不存在隐式类型转换的,是直接将子类切片给父类)

 但是我们要注意:基类对象不能赋值给派生类对象 基类的指针可以通过强制类型转换赋值给派生类的指针 (这样会有越界的风险)

    //基类对象不能赋值给派生类对象
    sobj = pobj;
    
    //基类对象不能引用给派生类对象
    Person p;
	Student& rs = p;

    //基类的指针可以通过强制类型转换赋值给派生类的指针
    pp = &sobj
    Student* ps1 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题
    ps1->_No = 10;
    
   

3.继承中的作用域

  • 1. 在继承体系中基类派生类都有独立的作用域
  • 2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问
  • 3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
  • 4. 注意在实际中在继承体系里面最好不要定义同名的成员

 就像下面这段程序:

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; // 学号
};
void Test()
{
	Student s1;
	s1.Print();
};

 这段程序能够正确运行:

 通过以前学习的知识我们也知道当同名变量出现在一起时会优先使用局部,而这里_num出现在两个不同的类域中,默认情况就在本域去寻找,指定类域后就在指定类域去寻找。这种情况就叫做隐藏。

再来看看一段程序:

// B中的fun和A中的fun不是构成重载,因为不是在同一作用域
// B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。
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);
};

由于fun()函数在不同作用域中,所以他们构成隐藏而不是重载。


4.派生类的默认成员函数

6 个默认成员函数, 默认 的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类
中,这几个成员函数是如何生成的呢?
  • 1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
  • 2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  • 3. 派生类的operator=必须要调用基类的operator=完成基类的复制。
  • 4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
  • 5. 派生类对象初始化先调用基类构造再调派生类构造。
  • 6. 派生类对象析构清理先调用派生类析构再调基类的析构。
  • 7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面讲解多态会详细讲解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。

class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}

	Person(string name= "张三", int age=18)
		:_name(name)
		, _age(age)
	{
		cout << "Person(string name= 张三, int age=18)" << endl;
	}

	Person(const Person& p)
		:_name(p._name)
		,_age(p._age)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		_name = p._name;
		_age = p._age;
		cout << "Person& operator=(const Person& p)" << endl;
		return *this;
	}

	~Person()
	{
		//如果有额外资源需要自己动手清理
		cout << "~Person()" << endl;
	}

protected:
	string _name;//  姓名
	int _age;//  年龄
};

class Student : public Person
{
public:
	Student(string name = "张三", int age = 18, int stuid=1)
		:Person(name, age)//这里要手动去调用基类的构造函数,
		,_stuid(stuid)
	{
		cout << "Student(int stuid=1)" << endl;
	}

	Student(const Student& s)
		:Person(s)//手动调用基类的拷贝构造,一种切片行为
		, _stuid(s._stuid)
	{
		cout << "Student(const Student& s)" << endl;
	}

	Student& operator=(const Student& p)
	{
		cout << "Student& operator=(const Student& p)" << endl;
		if (this != &p)
		{
			Person::operator=(p);//手动调用基类的赋值运算符重载,一种切片行为
			_stuid = p._stuid;
		}
		return *this;
	}

	~Student()
	{
		//this->~Student();//自己不要手动调用,编译器会自己调用,否则同一块资源有可能会被重复析构两次
		cout << "~Student()" << endl;
	}

protected:
	int _stuid; // 学号

};

不知道大家注意到了没有,由于上面程序子类继承父类的成员以及子类自己的成员都没有额外资源,所以这时就算我们不写,用系统默认生成的也能够完成任务,但是如果子类非继承成员需要额外资源的话这些都必须由我们自己实现。

如果父类没有默认构造,那么子类就要自己在初始化列表列表阶段显示调用。


5.继承与友元

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。

看下面一段程序:

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;
}
void main()
{
	Person p;
	Student s;
	Display(p, s);
}

上面程序中Display是People的友元,所以在Display可以访问到People的保护成员,但是Display不是Student的友元,所以不能够访问非继承下来的私有成员。要想访问还得在Student中加入Display的友元声明。


6. 继承与静态成员

基类定义了 static 静态成员,则整个继承体系里面只有一个这样的成员 。无论派生出多少个子
类,都只有一个 static 成员实例
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 Student
{
protected:
	string _seminarCourse; // 研究科目
};
void TestPerson()
{
	Student s1;
	Student s2;
	Student s3;
	Graduate s4;
	cout << " 人数 :" << Person::_count << endl;
	Student::_count = 0;
	cout << " 人数 :" << Person::_count << endl;
}

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

像上面的基类中定义了一个静态变量,在子类中所有成员共享这个变量,只会实例化出一份。


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

单继承:一个子类只有一个直接父类时称这个继承关系为单继承 。

 多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承。

 菱形继承:菱形继承是多继承的一种特殊情况。

 而菱形继承会有一些问题:大家想想,Student 和 Teacher各自保存了一份People的数据,那么Assitant中不就保存了两份People的数据吗?这样就不太合理了吧,如果People中数据很大时那不就浪费了很多空间去保存两份一样的数据吗?

我们来看下面这段代码:

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; // 主修课程
};
void Test()
{
	Assistant a;
	//a._name = "peter";// 这样会有二义性无法明确知道访问的是哪一个
	// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";
}

虽然上面的代码解决了二义性的问题,但是数据冗余问题还没有解决,那有啥办法可以解决菱形继承中数据冗余的问题呢?

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在 Student
Teacher 的继承 Person 时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地
方去使用。
class Person
{
public:
	string _name; // 姓名
};
class Student : virtual public Person
{
protected:
	int _num; //学号
};
class Teacher :virtual public Person
{
protected:
	int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};
void Test()
{
	Assistant a;
	a._name = "peter";
}

这里值得大家注意的是virtual究竟该用在哪一个类里。下面给大家一种继承关系,大家能分析下virtual应该加在哪里呢?

是在B和C之间加还是在C和D之间加?大家要想想这么一个问题,数据冗余是从哪儿开始出现的?是不是因为B和C继承了A中的数据,所以大家心里应该有了答案,应该在B和C之间加virtual。

这样就解决了菱形继承中数据冗余的问题。那菱形继承的原理是啥呢?

为了研究虚拟继承原理,我们给出了一个简化的菱形继承的继承体系,再借助 内存窗口观察对象成
员的模型。
下面给出这种模型:

这里温馨提示一下大家一定要在32位平台下进行验证(这是博主血的教训)

 这里不难看出_a已经重复冗余了,_a的数据被重复保留了两份。当我们加上virtual时:

 我们发现_a的数据已经只有了一份了,这时无论是对B的_a做修改还是对C的_a做修改,其实本质上他们指向的是同一个,就没有数据冗余了。

这时大家或许还有疑问,保存数据03和04上面那一行是什么鬼呀?

我们可以打开另外的监视窗口进行查看:

 其实03和04上面的地址就是虚基表指针,而他们指向了一个虚基表,这个虚基表里面存放的就是偏移量,那么这个偏移量又是啥?有啥作用吗?

存放偏移量是为了B和C都能快速找到他们公共的_a,我们看左边第一个内存窗口,从0X007EF710到0X007EF71C一共需要的字节是12个字节,而右边虚基表中恰好存放的是C(12个字节),同理从007EF708到0X007EF71C一共需要的字节是20字节,而右边虚基表中恰好存放的是14(20个字节)

为什么D中B和C部分要去找属于自己的A?那么大家看看当下面的赋值发生时,d是不是要去找出B/C成员中的A才能赋值过去?
D d;
B b = d;
C c = d;

这里d赋值给B类型的b和C类型的c实质是一种切片行为,那么d肯定就要去找他们各自对应的偏移量才能够正确的赋值过去。


8.继承的总结和反思

1. 很多人说 C++ 语法复杂,其实多继承就是一个体现。有了多继承 ,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不建议设计出多继承,一定不要设 计出菱形继承。否则在复杂度及性能上都有问题。
2. 多继承可以认为是 C++ 的缺陷之一,很多后来的很多 语言都没有多继承,如 Java
3. 继承和组合
  • public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
  • 组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。
优先使用对象继承,而不是类继承https://www.cnblogs.com/nexiyi/archive/2013/06/16/3138568.html
  • 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-box reuse)。术语白箱是相对可视性而言:在继承方式中,基类的内部细节对子类可见 。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。
  • 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复(black-box reuse),因为对象的内部细节是不可见的。对象只以黑箱的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。
  • 实际尽量多去用组合。优先使用对象组合有助于你保持每个类被封装,并被集中在单个任务上。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用继承,可以用组合,就用组合。

9.笔试面试题

  • 什么是菱形继承?菱形继承的问题是什么?

有一个基类被多个子类继承,这多个子类有两个及两个以上又被同一个子类所继承,构成这种类似于菱形关系的继承。菱形继承的问题是使用时有二义性以及数据冗余的问题。

  • 什么是菱形虚拟继承?如何解决数据冗余和二义性的 

菱形虚拟继承是用virtual来修饰数据冗余那一部分类,让他们被继承下来的成员共享同一块空间。解决数据冗余只能用菱形虚拟继承,二义性除了用菱形虚拟继承外还可以用类作用域限定符。

  •  继承和组合的区别?什么时候用继承?什么时候用组合?

继承允许你根据基类的实现来定义派生类的实现,基类的内部细节对子类可见 ,这种通过生成派生类的复用通常被称为白箱复用对象组合是类继承之外的另一种复用选择,新的更复杂的功能可以通过组装或组合对象来获得,对象的内部细节是不可见的,这种复用风格被称为黑箱复用

能用组合优先用组合,优先使用对象组合有助于你保持每个类被封装,并被集中在单个任务上。但有些类与类之间关系十分紧密的话就可以用继承,另外多态的实现也必须使用继承。

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

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

相关文章

linux(全志)初始环境到移植lvgl

一、 格式化TF卡 1. linux命令行格式化 1.1 找到U盘位置&#xff08;已挂载&#xff09; sudo fdisk -l 如图&#xff0c;我的在/dev/sdb 1.2 格式化U盘 sudo mkfs -t vfat /dev/sdb-t 后面是格式化为哪种文件系统格式&#xff0c;vfat就是fat32格式&#xff0c;最后…

Hashmap链表长度大于8真的会变成红黑树吗?

1、本人博客《HashMap、HashSet底层原理分析》 2、本人博客《若debug时显示的Hashmap没有table、size等元素时&#xff0c;查看第19条》 结论 1、链表长度大于8时(插入第9条时)&#xff0c;会触发树化(treeifyBin)方法&#xff0c;但是不一定会树化&#xff0c;若数组大小小于…

Win11电脑速度慢、延迟高怎么办?

作为新版的系统&#xff0c;Windows 11还需要更多的时间完善。不少用户反映升级了Win11后反而感觉速度慢&#xff0c;还有延迟或死机现象。 如果你使用Win11系统时也有这种感觉&#xff0c;那这篇文章就是为你提供的。 问题可能出在系统存储容量低、驱动程序已过时&#xff0…

APP渗透抓包

APP渗透抓包1.APP渗透测试原理2.安装安卓模拟器抓包2.1.安装模拟器2.2.设置代理下载证书2.2.1.burp suite设置代理2.2.2.浏览器设置代理2.2.3.下载证书2.3.模拟器安装证书2.3.1.移动证书2.3.2.证书设置2.4.设置代理2.4.1.设置burp suite代理2.4.2.夜神模拟器代理2.5.抓包测试2.…

JVM调优及垃圾回收GC

一、说一说JVM的内存模型。JVM的运行时内存也叫做JVM堆&#xff0c;从GC的角度可以将JVM分为新生代、老年代和永久代。其中新生代默认占1/3堆内存空间&#xff0c;老年代默认占2/3堆内存空间&#xff0c;永久代占非常少的对内存空间。新生代又分为Eden区、SurvivorFrom区和Surv…

Node.js安装与配置

Node.js安装与配置 前言 本篇博文记录了Node.js安装与环境变量配置的详细步骤&#xff0c;旨在为将来再次配置Node.js时提供指导方法。 另外&#xff1a;Node.js版本请根据自身系统选择&#xff0c;安装位置、全局模块存放位置和环境变量应根据自身实际情况进行更改。 Node…

spring(四)——————从spring源码角度去解释前面的疑问

前面两篇文章&#xff0c;我们从mybatis-spring的插件包出发&#xff0c;探究如何将第三方框架集成到spring中&#xff0c;也知道了mybatis中使用了FactoryBeanImportBeanDefifinitionRegistrarImport对mapper进行注入。 不过我们在前两篇文章中仍然遗留很多疑点&#xff0c;例…

Revit导出PDF格式图纸流程及“批量导出图纸”

一、Revit导出PDF格式图纸流程 1、点击左上方“应用程序菜单”即“R”图标&#xff0c;进择“打印”选项。 2、在弹出的对话框中&#xff0c;需要设置图纸“打印范围”&#xff0c;选择“所选的视图/图纸选项”&#xff0c;点击“选择”&#xff0c;按钮&#xff0c;选择我们需…

LESS模型与随机森林

模型学习 1 随机森林 https://blog.csdn.net/weixin_35770067/article/details/107346591? 森林就是建立了很多决策树&#xff0c;把很多决策树组合到一起就是森林。 这些决策树都是为了解决同一任务建立的&#xff0c;最终的目标也都是一致的&#xff0c;最后将其结果来平均…

Xline v0.2.0: 一个用于元数据管理的分布式KV存储

Xline是什么&#xff1f;我们为什么要做Xline&#xff1f; Xline是一个基于Curp协议的&#xff0c;用于管理元数据的分布式KV存储。现有的分布式KV存储大多采用Raft共识协议&#xff0c;需要两次RTT才能完成一次请求。当部署在单个数据中心时&#xff0c;节点之间的延迟较低&a…

08 SpringCloud 微服务网关Gateway组件

网关简介 大家都都知道在微服务架构中&#xff0c;一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢&#xff1f; 如果没有网关的存在&#xff0c;我们只能在客户端记录每个微服务的地址&#xff0c;然后分别去用。 这样的架构&#xff0c;会存…

Linux软件管理:源代码安装

前言 Linux上面的软件几乎都是经过GPL的授权&#xff0c;所以每个软件都提供源码 我们的系统中有一个http软件包&#xff08;上一篇文章中安装的&#xff09; 通过man手册我们知道了该软件包属于Apache&#xff0c;所以我们就可以进入它的官网中获取此源码 官网除了能获取源码…

IB学校获得IBO授权究竟有多难?

IB 学校认证之路&#xff0c;道阻且长 The road to IB school accreditation is long and difficult一所学校能获得IB授权必须经过IBO非常严格的审核&#xff0c;在办学使命&教育理念、组织架构、师资力量&授课技能、学校硬件设施和课程体系上完全符合标准才可获得授权…

英特尔 31.0.101.4125显卡驱动更新!

周更驱动的英特尔又来啦&#xff01;时隔一周英特尔为大家带来了31.0.101.4125版本的显卡驱动&#xff0c;支持《英雄连3》、《工人物语&#xff1a;新兴同盟》、《原子之心》、《狂野之心》、《如龙维新&#xff01;极》等游戏。 《如龙维新&#xff01;极》将在2月22日正式登…

功率放大器在lamb波方向算法的损伤定位中的应用

实验名称&#xff1a;基于PZT结Lamb波方向算法的损伤定位方法研究方向&#xff1a;损伤定位测试目的&#xff1a;Lamb波是在具有自由边界的固体板或层状结构中传输的一种弹性导波&#xff0c;由于其本身的传播特性&#xff0c;如沿传播路径衰减小&#xff0c;能量损失小&#x…

makefile简易教程

makefile简易教程 一、学习目标 达到多文件快速编译的需求&#xff0c;相关符号的意思&#xff0c;以及其它注意事项。 二、快速入门 2.1 基本概念 Makefile 是一个在Unix和Linux操作系统上使用的构建工具&#xff0c;用于自动化编译和构建源代码。 2.2 用处 通过Makefi…

Linux环境下(CentOS 7)安装MySQL

Linux环境下(CentOS 7)安装MySQL数据库 文章目录Linux环境下(CentOS 7)安装MySQL数据库一、安装MySQL数据库二、安装过程的中相关问题三、如何卸载已安装的MySQL四、参考链接一、安装MySQL数据库 1、下载mysql源安装包(version: 5.7.41 MySQL Community Server) wget http://…

ACM MM 相关内容的整理+汇总

目录一、网址二、重要时间点三、论文篇幅要求四、征稿主题五、论文格式相关要求六、论文模板修改成投稿模式上述参考七、模板使用相关八、关于图片方面的问题九、Review and Rebuttal十、ACM MM2022相关论文参考arxiv上 ACM MM2022 论文汇总一、网址 ACM MM2023 主页&#xff1…

阿里工作7年,一个30岁女软件测试工程师的心路历程

简单的先说一下&#xff0c;坐标杭州&#xff0c;14届本科毕业&#xff0c;算上年前在阿里巴巴的面试&#xff0c;一共有面试了有6家公司&#xff08;因为不想请假&#xff0c;因此只是每个晚上去其他公司面试&#xff0c;所以面试的公司比较少&#xff09; 其中成功的有4家&am…

嵌入式原理与应用期末复习汇总(附某高校期末真题试卷)

文章目录一、选择题二、填空题&#xff1a;三、判读题&#xff1a;四、简答题&#xff1a;五、程序设计题高校真题试卷第一套第二套第三套重修试卷一、选择题 1、为保证在启动服务器时自动启动DHCP进程&#xff0c;应对&#xff08; B &#xff09;文件进行编辑。 A、 /etc/rc…