0基础入门C++之类和对象中篇

news2024/11/25 19:22:05

目录

      • 1.类的6个默认成员函数
      • 2.构造函数
        • 2.1概念
        • 2.2特性
      • 3.析构函数
        • 3.1概念
        • 3.2特性
      • 4.拷贝构造函数
        • 4.1概念
        • 4.2 特性
      • 5.赋值运算符重载
        • 5.1运算符重载
        • 5.2赋值重载
        • 5.3赋值运算符重载特性
      • 6.const成员
      • 7.取地址及const取地址操作符重载

1.类的6个默认成员函数

通过类和对象上篇的学习,我们知道知道如果一个类中没有成员变量,也没有成员函数,啥也没有,那我们把它叫做空类。
比如 :class Date {};

那么空类中真的什么都没有吗?

并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

默认成员函数:即用户没有显式实现,编译器自动生成的成员函数称。

在这里插入图片描述

2.构造函数

2.1概念

现在有这样一个类:

class Date
{
public:
	void Init(int year, int month, int day)
	{
	
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/"  << _month  << "/"  <<  _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;
	d1.Init(2023,9,5);
	d1.Print();

	d2.Init(2023,8,18);
	d2.Print();

	return 0;
}

那对于一个类来说,我们实例化出来对象之后一般会对其进行一个初始化,但是有时候我们可能会忘记初始化,直接就对对象进行一些操作,不初始化直接用可能就会出现问题。

在这里插入图片描述
那么针对以上情况,C++给我们提供一种方法解决这个问题。

这个方法就是构造函数。构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证 每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。

2.2特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。

其特征如下:

  1. 函数名与类名相同。

也就是说定义好一个类,它的构造函数的函数名就已经确定,跟当前类的类名是相同的。

  1. 无返回值。

要注意这里说的无返回值不是说返回类型是void,而是根本就不写返回类型。

  1. 对象实例化时编译器自动调用对应的构造函数。

通过构造函数我们初始化对象就不用再手动初始化了,实例化对象时编译器会自动调用其对应的构造函数。

  1. 构造函数可以重载。

那么接下来我们就给上面的Date类写一个构造函数。

  Date()
  {
	_year = 1;
    _month = 1;
    _day = 1;

  }
  1. 无参构造函数

在这里插入图片描述
通过上图运行结果我们看出:这次我们并没有调用初始化函数,但是打印出来不是随机值,而是我们在构造函数中给定的值,说明我们实例化对象的时候确实自动调用构造函数进行初始化了。

  1. 带参构造函数
Date(int year, int month, int day)
	   {
		   _year = year;
		   _month = month;
		   _day = day;

	   }

在这里插入图片描述

注意: 如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明.

  1. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成

也就是说,构造函数不一定非要自己写,如果我们自己没有定义构造函数,编译器会自动生成一个。只不过是无参的。

那编译器会自动生成的话,我们以后是不是就不用自己写构造函数了?

答案是不可以

将上文中自己写的构造函数注释掉,直接运行程序:
在这里插入图片描述
我们可以看到调用编译器自动生成的构造函数是随机值。

实际上这个地方大家可以认为是C++在设计时出现了问题。

C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char...(包括各种指针类型),自定义类型就是我们使用class/struct/union等自己定义的类型
而编译器自动生成的构造函数不会对内置类型进行处理,对于自定义类型会处理,怎么处理?会去调用该自定义类型对应的默认构造函数

我们再看一个例子:

class Time
{
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本类型(内置类型)
	int _year;
	int _month;
	int _day;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;
	return 0;
}

这里的Date类它的成员变量里既有内置类型又有自定义类型。
但是我们现在并没有给Date类写构造函数,那我们在main函数里直接拿Date去创建一个对象,它自然就会去调用编译器自动生成的构造函数,那内置类型不做处理,这里还有一个自定义类型Time _t;,对于自定义类型,编译器会自动去调用它对应的默认构造函数。
我们运行一下验证一下结果:
在这里插入图片描述

那难道说内置类型不写构造函数就没法初始化了吗?

注意: C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。
在这里插入图片描述
在这里插入图片描述

  1. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。 注意: 无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

3.析构函数

3.1概念

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?

析构函数: 与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

下面我们举一个例子来帮助大家理解:

typedef int DataType;
class Stack
{
public:
	//构造函数
	Stack(size_t capacity = 4)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc fail");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	
private:
	DataType* _array;
	int _capacity;
	int _size;
};

int main()
{
	Stack s;
	s.Push(1);
	s.Push(2);
	return 0;
}

这里的对象s需要我们自己去销毁吗?
答案是不需要,因为s是定义在栈区上的局部变量,程序结束,它就随着main函数的栈帧自动销毁。
那析构函数的作用是啥呢?完成对象中资源的清理工作,什么意思?
像栈这样的对象,它里面是有在堆上动态开辟的空间,那经过C语言的学习我们都知道,这些空间是需要我们手动去释放的,否则可能会导致内存泄漏。
所以说,析构函数就是来帮我们干这件事情的。

3.2特性

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~。

一个类定义好之后,它的析构函数的函数名也是确定的,即在类名前面加上“~”。
“~”在C语言中是按位取反,表示它的功能和构造函数是相反的。

  1. 无参数无返回值类型
  2. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  3. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

下面我们就给刚才的栈写一个析构函数

~Stack()
	{
		free(_array);
		_array = NULL;
		_capacity = 0;
		_size = 0;
		
	}


为了方便观察是否自动调用了析构函数我们可以在代码中加入一行打印:
在这里插入图片描述

此时我们main函数里并没有显示调用~Stack函数
在这里插入图片描述
运行结果如下:
在这里插入图片描述

  1. 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数。
typedef int DataType;
class Stack
{
public:
	//构造函数
	Stack(size_t capacity = 4)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc fail");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack" << endl;
		free(_array);
		_array = NULL;
		_capacity = 0;
		_size = 0;
		
	}


	
private:
	DataType* _array;
	int _capacity;
	int _size;
};

class Date
{
private:
	// 基本类型(内置类型)
	int _year;
	int _month;
	int _day;
	// 自定义类型
	Stack _s;
};

int main()
{
	// Stack s;
	// s.Push(1);
	// s.Push(2);
	Date d1;
	return 0;
}

这里我们没有给Date显式定义析构函数,d1声明周期结束时,就会调用编译器自己生成的默认析构函数,那里面的内置类型不做处理,而自定义类型Stack _s;申请的资源需要清理,编译器自己生成的默认析构函数会调用Stack 类的析构函数:
在这里插入图片描述

  1. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如 Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

4.拷贝构造函数

4.1概念

我们再来回顾一下之前创建的日期类:

class Date
{
public:
       Date(int year = 1, int month = 1, int day = 1)
	   {
		   _year = year;
		   _month = month;
		   _day = day;

	   }


	void Print()
	{
		cout << _year << "/"  << _month  << "/"  <<  _day << endl;
	}
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

int main()
{
	Date d1;
	return 0;
}

现在有这样一个问题:如果我们现在想再创建一个对象,使这个对象和d1一样,或者说是d1的一份拷贝,应该怎么实现呢?

经过上面的学习,相信老铁们很容易想到,我们想创建一个和d1一样的新对象,可以用d1去初始化创建出来的新对象啊。是不是把构造函数的参数类型设置成类对象的类型就行了。
这就是拷贝构造。

拷贝构造函数: 只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

4.2 特性

拷贝构造函数也是特殊的成员函数,其特性如下:

  1. 拷贝构造函数是构造函数的一个重载形式。

那么我们现在先来写一个拷贝构造函数:

   Date(Date d)
      {
	      _year = d._year;
	      _month = d._month;
	      _day = d._day;
      }

那这样就可以了吗?
在这里插入图片描述

这里不行的原因是:在之前拷贝构造函数概念中我们提到参数类型必须是类类型对象的引用。
在这里插入图片描述

那为什么必须是类类型对象的引用呢?

  1. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。

在这里为什么会引发无穷递归呢?
在这里插入图片描述

此外对一个对象拷贝构造也可以这样写:

这里是引用

除此之外,我们还需要注意:

拷贝构造函数形参一般用const修饰:
在这里插入图片描述
相信这一点大家不难理解,形参是用来初始化我们新创建的对象的,加个const修饰形参d不会被修改。此外加上const 若传来的参数是const修饰的,我们依然可以接收。

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

那么默认生成的拷贝构造函数是否可靠呢?

这里我们再来看一下日期类:

首先我们将刚才实现的拷贝构造函数注释掉:

class Date
{
public:
       Date(int year = 1, int month = 1, int day = 1)
	   {
		   _year = year;
		   _month = month;
		   _day = day;

	   }

	//    Date(const Date& d)
    //   {
	//       _year = d._year;
	//       _month = d._month;
	//       _day = d._day;
    //   }




	void Print()
	{
		cout << _year << "/"  << _month  << "/"  <<  _day << endl;
	}
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

int main()
{
	// Date d1(2023,9,5);
	// Date d2(2023,8,18);
	//d1.Init(2023,9,5);
	Date d1;
	Date d2(d1);
	Date d3 = d1;
	d1.Print();
	//d2.Init(2023,8,18);
	d2.Print();
    d3.Print();
	return 0;
}

我们看一下结果
在这里插入图片描述

看到这里拷贝构造函数能一直可靠吗?

下面我们再来看一下Stack类:

typedef int DataType;
class Stack
{
public:
	//构造函数
	Stack(size_t capacity = 4)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc fail");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack" << endl;
		free(_array);
		_array = NULL;
		_capacity = 0;
		_size = 0;
		
	}


	
private:
	DataType* _array;
	int _capacity;
	int _size;
};



int main()
{
	Stack s;
	s.Push(1);
	s.Push(2);
	Stack s2(s);
	return 0;
}

对于Stack类我们也没有写拷贝构造函数,我们运行一下看一下结果:
在这里插入图片描述
会发现这里程序挂了, 那这里挂了的原因是什么呢?

其实这里根本原因就是出现在特性3上。

在特性3中有这样一句话:
在这里插入图片描述
在这里其实就是对逐个成员变量依次进行拷贝,里面存的是啥就把啥拷过去。

我们来对比一下Date类和Stack这两个类的拷贝:

对于Date类,浅拷贝是没有问题的。
在这里插入图片描述
一共12字节的内容依次拷贝过去就行

对于Stack类浅拷贝是存在问题的:
在这里插入图片描述
在这里出了作用域就会调用析构函数,而两个s1和s2中指针指向的空间就会被free两次,同样的我们在s1中入栈数据,s2里面就也有数据了(因为它俩用的是同一块空间),然后如果我们再用st2去入栈数据,此时s1_size前面已经++过,但是s2_size前面还是0,这样s2入的数据就把之前s1入的数据给覆盖了。

注意:
这里是s2先析构,我们知道s1和s2都是在栈上的(栈区),那栈区之所以叫栈区就是因为它在这个地方栈帧的建立也是遵循先进后出的这个顺序的,即后定义的会先进行析构。s2先析构,那堆上的这块空间就被释放了,但是接下来st也会进行它的析构,而此时虽然s1还保留了这块空间的地址,但是这块空间已经被释放,所以s1就是个野指针了。
所以为什么程序崩溃了,就是我们这里对野指针进行free了
在这里插入图片描述

因此:

类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请
时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

  1. 拷贝构造函数典型调用场景:

使用已存在对象创建新对象
函数参数类型为类类型对象
函数返回值类型为类类型对象

5.赋值运算符重载

5.1运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为: 关键字operator后面接需要重载的运算符符号。
函数原型: 返回值类型 operator操作符(参数列表)

下面我们依旧以日期类为例:

class Date
{
public:
       Date(int year = 1, int month = 1, int day = 1)
	   {
		   _year = year;
		   _month = month;
		   _day = day;

	   }

	void Print()
	{
		cout << _year << "/"  << _month  << "/"  <<  _day << endl;
	}
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

int main()
{
	Date d1(2023,9,5);
	Date d2(2023,8,18);

	d1.Print();
	d2.Print();

	return 0;
}

现在有两个对象d1,d2,大家思考一个问题,现在我们想比较这两个对象是否相等,要怎么实现呢?相信大家很容易想到用一个函数实现:

bool Equal(const Date& x1, const Date& x2)
{
	//...
}

但是在C++引入运算符重载之后呢,就使得我们还能够这样去实现:

bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1.day == d2.day;
}

这里会有一个小问题:
在这里插入图片描述
造成此问题的原因是:
Date类的这3个成员变量是私有的(private),所以在类外面是不能访问的。
那怎么解决?
我们可以在类里写一个Get方法(函数),通过Get方法来访问,或者直接把private访问限定符去掉。
我们这里先把private注释下:
在这里插入图片描述

现在我们来调用一下:

这里是引用
注意:因为这里<<的优先级比==高,所以要加括号。

但是这里直接重载到了全局,我们把成员变量全部公有了,封装性又如何体现呢?

所以这里比较好的一种方法是:我们直接重载到类里面,即重载成成员函数。

但是这里又出现了一个小问题如果直接把函数封装在类里:

这里是引用
这里我们重载的是==运算符,正常情况下只有两个操作数,所以只需要两个参数就够了。
那这里不就是两个参数嘛?
不要忘了,这里还有一个隐藏参数。什么隐藏参数,就是this指针。
C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象)
所以我们这里只需给一个参数。

bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}

注意:

  1. 不能连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符至少有一个类类型的参数
  3. 用于内置类型的运算符,其含义不能重载改变,例如:内置的整型+,不能改变其含义
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1个,因为成员函数的第一个参数为隐藏的this
  5. .* :: sizeof ?: .注意这5个运算符不能重载,这个经常在笔试选择题中出现。

5.2赋值重载

参数类型:const 类对象的引用,传递引用可以提高传参效率
返回值类型:类类型&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
最好检测一下是否是自己给自己赋值,并进行一下处理
返回*this:返回的结果用于支持连续赋值

那么日期类的赋值重载就是:

	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}

但是有时候呢不排除有人可能会把自己赋值给自己,于是它调用函数白白进行了一次拷贝,我们对此进行改进

	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}


5.3赋值运算符重载特性

  1. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝(浅拷贝)。

注意:默认生成的赋值重载对于内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用其对应类的赋值运算符重载完成赋值。

那么下面这种情况会调用拷贝构造还是赋值重载?

这里是引用
这里用了赋值=,但是是拷贝构造。
什么时候是调赋值重载呢?
是我们用已经实例化出来的对象进行相互赋值的时候,调用赋值重载。而当我们用一个已经实例化出来的对象去初始化一个新对象的时候,调的是拷贝构造。

  1. 赋值运算符只能重载成类的成员函数不能重载成全局函数

原因:赋值重载如果在类里不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。
在这里插入图片描述

6.const成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数 隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

以刚才的赋值重载函数为例:

Date& operator=(const Date& d) const
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

在这里插入图片描述

7.取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

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

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

相关文章

操作系统——操作系统内存管理基础

文章目录 1.内存管理介绍2.常见的几种内存管理机制3.快表和多级页表快表多级页表总结 4.分页机制和分段机制的共同点和区别5.逻辑(虚拟)地址和物理地址6.CPU 寻址了解吗?为什么需要虚拟地址空间? 1.内存管理介绍 操作系统的内存管理主要是做什么&#xff1f; 操作系统的内存…

solidwords(6)

从右视图开始&#xff0c;分上下两部分 标题 这里的薄壁要留意一下怎么算的&#xff08;单向&#xff1a;默认向内&#xff1b;如果想向外记得选反向&#xff09;

Vue2+Vue3笔记(尚硅谷张天禹老师)day01

只是记录&#xff0c;初心是为了让页面更好看,会有错误 环境准备 下载vue:Vue下载 下面两个是可选的,主要是我想让控制台干净点 vue_dev_tool安装 vue_dev_tool安装 : Vue 控制台出现You are running Vue in development mode. Make sure to turn on production mode when dep…

unity之Input.GetKeyDown与Input.GetKey区别

文章目录 Input.GetKeyDown与Input.GetKey区别 Input.GetKeyDown与Input.GetKey区别 Input.GetKey 和 Input.GetKeyDown 是 Unity 中用于检测按键状态的两个不同函数。它们之间的区别在于何时触发。 Input.GetKey(KeyCode key): 这个函数会在用户按住指定的键时触发&#xff0…

CountDownLatch和CyclicBarrie

前置提要 什么是闭锁对象 闭锁对象&#xff08;Latch Object&#xff09;是一种同步工具&#xff0c;用于控制线程的等待和执行顺序。闭锁对象可以让一个或多个线程等待&#xff0c;直到特定的条件满足后才能继续执行。 在Java中&#xff0c;CountDownLatch就是一种常见的闭锁对…

【AI大模型】训练Al大模型

大模型超越AI 前言 洁洁的个人主页 我就问你有没有发挥&#xff01; 知行合一&#xff0c;志存高远。 目前所指的大模型&#xff0c;是“大规模深度学习模型”的简称&#xff0c;指具有大量参数和复杂结构的机器学习模型&#xff0c;可以处理大规模的数据和复杂的问题&#x…

C语言刷题指南(三)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

JS-Array数组方法reduce()

reduce方法 // 可以与箭头函数一起使用 array.reduce((total,curVal) > total curVal, initVal) array.reduce(function(total, currentValue, currentIndex, arr), initialValue) 例子&#xff1a; // a:总和/累加项 // c&#xff1a;每一项的值 const allCount compu…

实验三 nfs 服务器环境搭建

nfs 服务器环境搭建 nfs&#xff08;Network File System&#xff09;即网络文件系统&#xff0c;其基于UDP/IP 使用nfs能够在不同计算机之间通过网络进行文件共享&#xff0c;能使使用 者访问网络上其它计算机中的文件就像在访问自己的计算机一样。 【实验目的】 掌握 nfs 环…

RT1052的XBAR

文章目录 XBAR2函数2.1 XBARA_Init2.2XBARA1_Signal_Set XBAR XBAR 是 RT1052 芯片自带的内部外设交错开关矩阵 它可以将 RT1052 内部外设的输出&#xff08;或 IO 口的输入&#xff09;映射到另外一部分内部外设的输入&#xff08;或 IO 口的输出&#xff09;上&#xff0c;…

WordPress用于您的企业网站的优点和缺点

如今&#xff0c;WordPress 被广泛认为是一个可靠、可扩展且安全的平台&#xff0c;能够为商业网站提供支持。然而&#xff0c;许多人质疑 WordPress 是否是适合企业的平台。 这就是我们创建本指南的原因。通过探索 WordPress 的优点和缺点&#xff0c;您可以确定世界上最受欢…

低代码自动化解析:企业所需了解的全面指南

根据2020年以来与低代码技术相关的积极趋势&#xff0c;Gartner预测到2023年低代码开发技术市场将增长20%。此外&#xff0c;他们还预计&#xff0c;到2026年&#xff0c;非正式IT部门的开发人员将占低代码开发工具用户群至少80%的比例&#xff0c;而这一比例在2021年为60%。基…

服务器感染了.360勒索病毒,如何确保数据文件完整恢复?

引言&#xff1a; 随着科技的不断进步&#xff0c;互联网的普及以及数字化生活的发展&#xff0c;网络安全问题也逐渐成为一个全球性的难题。其中&#xff0c;勒索病毒作为一种危害性极高的恶意软件&#xff0c;在近年来频频袭扰用户。本文91数据恢复将重点介绍 360 勒索病毒&a…

C++快速回顾(二)

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》&#xff0c;结合我自己的工作学习经历&#xff0c;我准备写一个音视频系列blog。C/C是音视频必…

HDU-7314 2023“钉耙编程”杭电多校赛(4)Data Generation

HDU-7314 2023“钉耙编程”杭电多校赛&#xff08;4&#xff09;Data Generation 题目大意 给定 n n n和 m m m&#xff0c;求下面的算法中 a n s ans ans的期望值模 998244353 998244353 998244353后的结果。 有 T T T组数据。 1 ≤ T ≤ 1 0 5 , 1 ≤ n ≤ 1 0 18 , 0 ≤ m…

一种新型的4H-SiC超结共模场效应晶体管(UMOSFET),具有异质结二极管,以提高反向恢复特性

标题&#xff1a;A novel 4H-SiC super junction UMOSFET with heterojunction diode for enhanced reverse recovery characteristics 摘要 摘要—本文提出并通过数值模拟研究了一种新型的碳化硅&#xff08;SiC&#xff09;超结共模场效应晶体管&#xff08;UMOSFET&#xf…

Python批量爬虫下载文件——把Excel中的超链接快速变成网址

本文的背景是&#xff1a;大学关系很好的老师问我能不能把Excel中1000个超链接网址对应的pdf文档下载下来。虽然可以手动一个一个点击下载&#xff0c;但是这样太费人力和时间了。我想起了之前的爬虫经验&#xff0c;给老师分析了一下可行性&#xff0c;就动手实践了。    没…

企业展示小程序搭建指南

如今&#xff0c;移动互联网的快速发展&#xff0c;为企业展示提供了更多元化的方式。除了传统的宣传手段&#xff0c;企业还可以借助小程序来展示自己的实力和产品。本文将为大家介绍一种简单的DIY小程序的方法&#xff0c;让企业能够快速打造自己的展示平台。 首先&#xff0…

在线SHA384计算哈希(不可逆的加密又称摘要)工具

具体请前往&#xff1a;在线计算Sha384摘要工具

leetcode做题笔记92. 反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 思路一&#xff1a;头插法 struct ListNode *reverseBetween(struct ListNode *h…