c++继承知识点

news2025/1/10 16:05:26

目录

  • 1.继承的概念及定义
    • 1.1继承的概念
    • 1.2 继承定义
      • 1.2.1定义格式
      • 1.2.2继承关系和访问限定符
      • 1.2.3继承基类成员访问方式的变化
  • 2.基类和派生类对象赋值转换
  • 3.继承中的作用域
  • 4.派生类的默认成员函数
  • 5.继承与友元
  • 6. 继承与静态成员
    • 如何定义一个不被继承的类
  • 7.继承的一个题目
  • 8. 复杂的菱形继承及菱形虚拟继承
    • 继承种类
    • 代码
    • 虚拟继承解决数据冗余和二义性的原理
  • 9.继承的总结和反思
  • 10.问答

1.继承的概念及定义

1.1继承的概念

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

class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	string _name = "peter"; // 姓名
	int _age = 18; // 年龄
};
// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了
//Student和Teacher复用了Person的成员。下面我们使用监视窗口查看Student和Teacher对象,可
//以看到变量的复用。调用Print可以看到成员函数的复用。
class Student : public Person
{
protected:
	int _stuid; // 学号
};
class Teacher : public Person
{
protected:
	int _jobid; // 工号
};
int main()
{
	Student s;
	Teacher t;
	s.Print();
	t.Print();
	return 0;
}

1.2 继承定义

1.2.1定义格式

下面我们看到Person是父类,也称作基类。Student是子类,也称作派生类。
在这里插入图片描述

1.2.2继承关系和访问限定符

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

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

类的访问限定符 (protected / private的成员) --> 类里面可以访问,类外面不可以访问

在继承里面
	基类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继承下来的成员都只能在派生类的类里
    面使用,实际中扩展维护性不强。
// 实例演示三种继承关系下基类成员的各类型成员访问关系的变化
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; // 学号
};

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

  • 派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片
    或者切割。寓意把派生类中父类那部分切来赋值过去。
  • 基类对象不能赋值给派生类对象。
  • 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类
    的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(RunTime Type Information)的 dynamic_cast 来进行识别后进行安全转换。(ps:后面讲解,这里先了解一下)
    在这里插入图片描述
// 基类
class Person
{
protected:
	string _name; // 姓名
	string _sex; // 性别
	int _age; // 年龄
};

// 派生类
class Student : public Person
{
public:
	int _No; // 学号
};
void Test()
{
	Student sobj;


	/// 1.子类对象可以赋值给父类对象/指针/引用

	//这里虽然是不同类型,但不是隐式类型转换
	//这里算是一个特殊支持,语法天然支持

	Person pobj = sobj;
	Person* pp = &sobj; // 切片 pp指向子类中包含父类成员变量的一部分
	Person& rp = sobj; // 从引用这里可以看出不存在类型转换

//比如:
	// int i = 10;
	// double& di = i;  // 这里会报错,上面的引用不会报错 
	// 因为这里存在隐式类型转换,会产生临时变量,具有常性,需要加const




	///2.基类对象不能赋值给派生类对象

	//子类可以赋值给父类,但是父类不能赋值给子类
	//因为子类继承了父类,子类含有父类的成员,可以将对应的成员变量给父类
	//但是父类没有子类的成员,不能赋值给子类,子类中的成员变量,父类给不了值
	sobj = pobj; /// 报错(就算强制转换也不能将父类赋值给子类)




	/// 3.基类的指针可以通过强制类型转换赋值给派生类的指针
	// Person* pp  person 为父类  student  sobj; 为子类
	pp = &sobj;
	Student * ps1 = (Student*)pp; // 这种情况转换时可以的。
	ps1->_No = 10;
	pp = &pobj;



	Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题
	ps2->_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 << " 学号:" << _num << endl; // 999
		cout << " 身份证号:" << Person::_num << endl; // 111
	}
protected:
	int _num = 999; // 学号
};

// 1、两个fun构成函数重载? -- 不对 函数重载要求在同一作用域
// 2、两个fun构成隐藏  -- ok

class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};

class B : public A
{
public:
	void fun(int i)
	{
		cout << "func(int i)->" << i << endl;
	}
};

void main()
{
	B b;
	b.fun(10);
	b.A::fun();
};

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

6个默认成员函数,“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?

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

在这里插入图片描述

在这里插入图片描述

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;
	}
	
	// 拷贝 如何需要传父类对象,但是如何从子类中拿到父类对象,直接传子类对象s就可以,因为存在赋值转换切片
	// c++支持切片所以可以这样做,还有就是将子类指针(this)强转为父类person*  解引用获取父类部分(类型决定看多大)
	//Student s2(s);  s是已经存在的子类 Student 里面有继承的 父类 Person成员
	Student(const Student& s)
		:Person(s)  // 调用父类的拷贝构造
		, _num(s._num)
	{
		cout << "Student(const Student& s)" << endl;
	}

	// 赋值
	Student& operator=(const Student& s)
	{
		if (this != &s)
		{
			// operator=(s); 会造成死递归,因为调用的是子类的赋值,需要加父类访问限定符
			Person::operator=(s); 

			_num = s._num;
		}

		cout << "Student& operator=(const Student& s)" << endl;

		return *this;
	}

	// 子类的析构的函数跟父类析构函数构成隐藏。
	// 由于后面多态的需要,析构函数名字会统一处理成destructor()
	~Student()
	{
		// 构造是先构造父类在构造子类,析构就因该先析构子类在析构父类
		// 不需要显示调用父类析构函数
		// 每个子类析构函数后面,会自动调用父类析构函数,这样才能保证先析构子类,再析构父类
		//Person::~Person();

		// ...处理子类自己的
		cout << "~Student()" << endl;
	}

	//Student* operator&()
	//{
	//	return this;
	//}


protected:
	int _num;

	// int* _ptr;
};


int main()
{
	Student s1("张三", 1);

	//Student s2(s1);
	Student s2 = s1;

	Student s3("李四", 2);

	s1 = s3;

	cout << &s1 << endl;

	return 0;
}

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);
}

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; // 学号
};

int main()
{
	Person p;
	Student s;

	p._name = "张三";
	cout << s._name << endl;

	cout << Student::_count << endl;
	++Person::_count;
	cout << Student::_count << endl;

	cout << &Person::_count << endl;
	cout << &Student::_count << endl;

	return 0;
}

如何定义一个不被继承的类

// C++98
// 1、父类构造函数私有-- 子类是不可见
// 2、子类对象实例化,无法调用构造函数
class A
{
private:
	A()
	{}

protected:
	int _a;
};

class B : public A
{};

int main()
{
	//没有实例化编译不会报错
	B bb; // error 当实例化后就会报错
	return 0;
}


// C++11
// final
class A final
{
private:
	A()
	{}

protected:
	int _a;
};

class B : public A
{};

int main()
{
	// 父类加 final关键字
	// 不管是否实例化都会报错,编译阶段就会检查到语法错误
	//B bb;
	return 0;
}

7.继承的一个题目

在这里插入图片描述

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

继承种类

单继承:一个子类只有一个直接父类时称这个继承关系为单继承
在这里插入图片描述

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
在这里插入图片描述

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

在这里插入图片描述

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

代码

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()
{

	Assistant at;

	/// 这样会有二义性无法明确知道访问的是哪一个,是Student的,还是Person的,会报错
	at._name = "张三"; 


	// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
	at.Student::_name = "张三";
	at.Teacher::_name = "李四";
 
	return 0;
}

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在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; // 主修课程
};
int main()
{

	Assistant at;
	at._name = "张三"; // 用虚拟继承就不会报错了
 
	return 0;
}

虚拟继承解决数据冗余和二义性的原理

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

class A
{
public:
	int _a;
};

// class B : public A
class B : virtual public A
{
public:
	int _b;
};

// class C : public A
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._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

下图是菱形继承的内存对象成员模型:这里可以看到数据冗余
在这里插入图片描述
下图是菱形虚拟继承的内存对象成员模型:这里可以分析出D对象中将A放到的了对象组成的最下
面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指
向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量
可以找到下面的A。

在这里插入图片描述下面是上面的Person关系菱形虚拟继承的原理解释:
在这里插入图片描述

9.继承的总结和反思

  1. 很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱
    形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不建议设计出多继承,一定不要设
    计出菱形继承。否则在复杂度及性能上都有问题。
  2. 多继承可以认为是C++的缺陷之一,很多后来的OO语言都没有多继承,如Java。
  3. 继承和组合.
  • public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
  • 组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。
  • 优先使用对象组合,而不是类继承 。
  • 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称
    为白箱复用(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,基类的
    内部细节对子类可见 。继承一定程度破坏了基类的封装,基类的改变,对派生类有很
    大的影响。派生类和基类间的依赖关系很强,耦合度高。
  • 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象
    来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复
    用(black-box reuse),因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。
    组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被
    封装。
  • 实际尽量多去用组合。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有
    些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用
    继承,可以用组合,就用组合。
// Car和BMW Car和Benz构成is-a的关系
class Car {
protected:
	string _colour = "白色"; // 颜色
	string _num = "陕ABIT00"; // 车牌号
};
class BMW : public Car {
public:
	void Drive() { cout << "好开-操控" << endl; }
};
class Benz : public Car {
public:
	void Drive() { cout << "好坐-舒适" << endl; }
};
// Tire和Car构成has-a的关系
class Tire {
protected:
	string _brand = "Michelin"; // 品牌
	size_t _size = 17; // 尺寸
};
class Car {
protected:
	string _colour = "白色"; // 颜色
	string _num = "陕ABIT00"; // 车牌号
	Tire _t; // 轮胎
};

class C
{
	//...
};
//组合
class D
{
protected:
	C _c;
	//... 
};

10.问答

  1. 什么是菱形继承?菱形继承的问题是什么?
  2. 什么是菱形虚拟继承?如何解决数据冗余和二义性的
  3. 继承和组合的区别?什么时候用继承?什么时候用组合?

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

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

相关文章

目标检测之YOLOv2算法分析

要点 Batch Normalization 训练 若batchsize64,某一层的某一个神经元会输出64个响应值&#xff0c;对这64个响应值求均值&#xff0c;标准差&#xff0c;然后标准化&#xff0c;对标准化的结果乘λβ\lambda \betaλβ,其中λ\lambdaλ和 β\betaβ是需要训练的参数&#xf…

Windows平台RTMP、RTSP播放器录像模块精细化控制

技术背景 上篇文章&#xff0c;我们介绍了Unity平台RTMP、RTSP播放器录像功能&#xff0c;这里&#xff0c;我们详细的介绍下&#xff0c;做个RTSP或RTMP拉流端录像模块有哪些需要考虑的技术点&#xff1f; 在我们常规的考量&#xff0c;RTMP或RTSP流录制&#xff0c;无非就是…

在gitee上新建仓库并上传文件

一、进入到自己gitee的个人主页&#xff0c;点击图示新建仓库 二、根据图示操作&#xff0c;最后点击创建 三、如果没有配置git全局设置&#xff0c;需要配置一下(配置过的可以跳过这一步) 四、打开你要上传的文件&#xff0c;在里面右击鼠标&#xff0c;点击如图所示 五、输入…

spring之Bean的循环依赖问题

文章目录一、Bean的循环依赖之Set注入模式下1、Husband类2、Wife类3、Spring配置文件4、测试类5、测试结果6、结论二、Bean的循环依赖之构造方法注入模式下1、Husband类2、Wife类3、Spring配置文件4、测试类5、运行结果三、Spring解决循环依赖的机理三级缓存&#xff08;面试常…

PyQt5 基本布局管理 及 信号槽机制

一&#xff1a;布局设计 & 信号槽机制 效果实现如下&#xff1a; 对于窗口整体设计左右布局 对于左边布局&#xff0c;包括有水平布局(用户信息 左上方一块)垂直布局(多个按钮 左下方一块) 对于右边布局&#xff0c;主要是窗口切换&#xff0c;通过按下左边布局的左下方侧按…

SQLAlchemy连接MySQL及记录的查询、更新、删除、多表关联查询

SQLAlchemy是Python的ORM库&#xff0c;支持多种数据库。 建立连接 连接MySQL要用到Engine&#xff0c;Engine集成了连接池pool和方言Dialect&#xff08;支持不通数据库的SQL语法&#xff09;&#xff0c;最后都统一成标准DBAPI。 from sqlalchemy import create_engine en…

TypeScript

现在说起TypeScript想必大家都不会陌生的&#xff0c;当初从碎片信息中了解TypeScript&#xff0c;我认为他的变量声明和Rust语言有几分相似&#xff0c;是一门比较严格的语言&#xff0c;今天正式的来学习他 JavaScript易学习&#xff0c;易用&#xff0c;以至于大多数人对于…

软件体系结构 思维导图

软件体系结构 思维导图 软件体系结构思维导图 源文件放在 GitHub 仓库 使用 Xmind 即可打开查看 课程评价 比较抽象和理论化&#xff0c;如果光看 PPT 肯定看不懂&#xff0c;得听课或者看视频 后面实验试图基于 SpringBoot 去实战教学&#xff0c;可惜没系统学过只能照搬…

Kafka Consumer开发

Kafka Consumer - 消费者 跟生产者一样&#xff0c;消费者也属于kafka的客户端&#xff0c;不过kafka消费者是从kafka读取数据的应用&#xff0c;侧重于读数据。一个或多个消费者订阅kafka集群中的topic&#xff0c;并从broker接收topic消息&#xff0c;从而进行业务处理。今天…

一种嵌入式项目的参数保存方案

设计背景 嵌入式项目中&#xff0c;为了保证系统的正常运转&#xff0c;通常需要保存一部分数据至非易失存储设备如flash中。此处提供了一种通用的方案用于快速在项目中集成参数保存功能&#xff0c;该方案有以下几点特征&#xff1a; 接口简便&#xff0c;方便快速集成以及使用…

东北大学2023分布式操作系统实验

1.实验目的 建立伪分布式&#xff08;有条件的可以建立分布式环境&#xff09;的Hadoop环境&#xff0c;并成功运行示例程序。 2.Hadoop简介 2.1 Hadoop项目基础结构 在其核心&#xff0c;Hadoop主要有两个层次&#xff0c;即&#xff1a; 加工/计算层(MapReduce)存储层(Ha…

Python pandas有几千个库函数,你用过几个?(1)

对Python的 pandas 库所有的内置元类、函数、子模块等全部浏览一遍&#xff0c;然后挑选一些重点学习一下。我安装的库版本号为1.3.5&#xff0c;如下&#xff1a; >>> import pandas as pd >>> pd.__version__ 1.3.5 >>> print(pd.__doc__)pandas…

C++ STL vector list set map容器循环通过迭代器删除元素注意事项

先说说写这篇博客的原因吧&#xff0c;同事转部门了&#xff0c;把他手头的工作交接给了我。他以前维护的一个模块&#xff0c;会将外部输入的数据缓存起来分段处理&#xff0c;处理完了就会清除缓存数据&#xff0c;最近出现了一个bug&#xff0c;缓存数据一直不清除&#xff…

【SpringMVC】非注解的处理器映射器和适配器

项目目录 1.导入的依赖 pom.xml <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><…

【K3s】第2篇 一篇文章学习实践K3s部署安装

目录 1、docker安装 2、docker-compose安装 3、K3s安装 3.1 k3s与install.sh文件准备 3.2 k3s 安装步骤 4、查看k3s部署状态 1、docker安装 方式一 https://fanjufei.blog.csdn.net/article/details/123500511https://fanjufei.blog.csdn.net/article/details/123500511 …

12.24

接口测试 ​ <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width…

Unity3D异步加载场景SceneManager.LoadSceneAsync()卡住,并不异步,获取process直接到0.9的问题

问题阐述&#xff1a; 一般来说&#xff0c;在加载场景的时候&#xff0c;会因为所加载资源的大小、复杂度、电脑配置等因素导致加载过程耗费一定的时间。虽然这个加载时间是不可避免的&#xff0c;但是在这一小段卡着的时间里如果就这样卡着的话会大大降低玩家体验。 所以很多…

(matlab编程基础)数组的基本操作

目录 1、数组寻址 2、数组元素删除 3、数组查找和排序 &#xff08;1&#xff09;数组查找 &#xff08;2&#xff09;数组排序 4、数组运算 5、数组操作函数 数组操作主要从以下5部分进行介绍:数组寻址、数组元素的删除、数组查找和排序、数组运算和数组操作函数。 1、…

PS CS6视频剪辑基本技巧(五)添加logo、动画和画中画

系列讲座导读 PS CS6视频剪辑基本技巧&#xff08;一&#xff09;CS6可以实现的视频剪辑功能 PS CS6视频剪辑基本技巧&#xff08;二&#xff09;视频剪接和添加图片 PS CS6视频剪辑基本技巧&#xff08;三&#xff09;添加声音和字幕 PS CS6视频剪辑基本技巧&#xff08;四&am…

RMQ - ST表

RMQ - ST表 1、RMQ 简介 RMQ (Range Minimum / Maximum Query) 问题是指&#xff1a;对于长度为 nnn 的数列 AAA&#xff0c;回答若干询问 (A,i,j)(A, i, j)(A,i,j) (1≤i,j≤n)(1≤i,j≤n)(1≤i,j≤n)&#xff0c;返回数列 A 中区间在 [i,j][i,j][i,j] 中的最小 (大) 值所在…