【C++实战项目】Date日期类 --- 运算符重载的深入探索

news2024/11/24 12:44:43

在这里插入图片描述

📷 江池俊:个人主页
🔥 个人专栏:✅C++那些事儿 ✅Linux技术宝典
🌅 此去关山万里,定不负云起之望


在这里插入图片描述

文章目录

    • 引言
    • 一、为什么需要运算符重载?
    • 二、日期类的实现
      • 1. 基本框架
      • 2. 预备工作
      • 3. Date 类中六大默认成员函数的使用
        • 3.1 全缺省的构造函数
        • 3.2 拷贝构造函数
        • 3.3 析构函数
        • 3.4 赋值运算符重载
        • 3.5 const 成员函数
        • 3.6 取地址操作符重载和const取地址操作符重载
      • 4. 运算符重载
        • 4.1 += 和 + 运算符重载
        • 4.2 -= 和 - 运算符重载
        • 4.3 前置++ 和 后置++ 运算符重载
        • 4.4 前置-- 和 后置-- 运算符重载
        • 4.5 > 和 == 运算符重载
        • 4.6 >= 、< 、<= 和 != 运算符重载
        • 4.7 日期-日期
        • 4.8 流插入 << 和 流提取 >> 运算符重载
    • 5. 日期类源码
      • 5.1 Date.h文件
      • 5.2 Date.cpp 文件
    • 总结


引言

在C++编程中,运算符重载是一种强大的功能,它允许我们为自定义的数据类型定义运算符的行为。这种特性在创建像日期(Date)这样的类时尤其有用,因为它允许我们更自然、更直观地操作这些类的实例。通过日期类我们还能够实现一个简单的日期时间计数器的功能,想必大家都很期待接下来的内容。

在这里插入图片描述

在本篇博客中,我们将深入探索如何为Date类重载运算符,并了解其中的一些最佳实践和潜在陷阱。

Date.h文件下放日期类的声明代码,Date.c文件下放日期类的实现代码


一、为什么需要运算符重载?

运算符重载可以让我们使用更直观、更自然的方式来操作日期。

在创建日期类时,我们可能希望执行如下操作:

  • 对两个日期进行加法运算以得到一个新的日期(例如,将5天加到今天的日期上)。
  • 比较两个日期以确定哪个日期更早或更晚。
  • 从一个日期中减去另一个日期以得到它们之间的时间差。
  • 等等…

为了实现这些操作,我们需要为Date类重载相应的运算符,如+、-、<等。


二、日期类的实现

1. 基本框架

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month) const;
	// 检查日期是否合法
	bool CheckInvalid();

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);

	// 拷贝构造函数
	// d2(d1)
	Date(const Date& d);
	
	// 赋值运算符重载
	// d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);

	// 析构函数
	~Date();

	// ======== 有关日期计算的运算符重载 ========
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();

	// =========== 比较运算符的重载 ==========
	// >运算符重载
	bool operator>(const Date& d) const;
	// ==运算符重载
	bool operator==(const Date& d) const;
	// >=运算符重载
	bool operator >= (const Date& d) const;
	// <运算符重载
	bool operator < (const Date& d) const;
	// <=运算符重载
	bool operator <= (const Date& d) const;
	// !=运算符重载
	bool operator != (const Date& d) const;

	// 日期-日期 返回天数
	int operator-(const Date& d);

	// 打印,const成员函数修饰的是成员函数隐含的this指针,表明不能修改任何成员变量
	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	// 友元声明,可以在类的任何位置
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
private:
	int _year;
	int _month;
	int _day;
};

// 类外声明
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

2. 预备工作

在构造日期类时我们很有可能不小心传入错误的日期时间,比如 2023-02-29 或 2024-4-31这样的时间,所以为了确保日期的正确性,在构造函数中我们需要检查日期的合法性,因此在写构造函数前需要先实现两个成员函数:

  1. CheckInvalid() 函数:功能是检查日期是否合法
  2. GetMonthDay(int year, int month) 函数:功能是获取某年某月的天数
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month) const
{
	static int days[13] = { 0,31,28,31,30,31,30,31,30,31,31,30,31 };

	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}

	return days[month];
}

// 检查日期是否合法
bool Date::CheckInvalid()
{
	if (_year <= 0
		|| _month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month))
	{
		return false;
	}
	return true;
}

注意:这里 days 数组被声明为静态数组,静态数组在程序的生命周期内只会被初始化一次。由于 GetMonthDay 函数被频繁调用,将其声明为静态可以确保它只在程序开始时分配一次内存,而不是每次调用函数时都重新分配。这可以提高空间效率

3. Date 类中六大默认成员函数的使用

3.1 全缺省的构造函数
// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1)
{
	_year = year;
	_month = month;
	_day = day;

	if (!CheckInvalid())
	{
		cout << *this << "构造日期非法" << endl;
		exit(-1);
	}
}

通过构造函数即可对实例化对象进行初始化。

3.2 拷贝构造函数

拷贝构造:同类型的一个已经存在的对象去初始化一个新的要创建的对象

// 拷贝构造函数
// d2(d1)
Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
3.3 析构函数
// 析构函数
~Date()
{
	//cout << "~Date()" << endl;
}

日期类并 没有申请资源(动态开辟内存,打开文件等),所以这里的析构函数可写可不写,系统默认生成的就够用。

3.4 赋值运算符重载

赋值重载:已经存在的两个对象,一个拷贝赋值给另一个

// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& operator=(const Date& d)
{
	if (this != &d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}
3.5 const 成员函数
// 举例:
// 打印,const成员函数修饰的是成员函数隐含的this指针,表明不能修改任何成员变量
void Print() const
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

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

如果我们只需要访问成员变量而非修改成员变量,那么此时我们就可以使用 const成员函数 来提高代码的健壮性。

3.6 取地址操作符重载和const取地址操作符重载
// 取地址操作符重载
Date* operator&()
{
	return this;
	//return nullptr;
}

// const取地址操作符重载
const Date* operator&()const
{
	return this;
	//return nullptr;
}

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

这里以注释的两个return语句为例,可以返回空指针给别人,让对方找不到指定的类对象。(所以大多数情况下我们都不需要重载这两个成员函数,使用编译器默认生成的即可


4. 运算符重载

此处详细讲解 += 和 + 运算符的重载,-= 和 - 运算符的重载与其类似。

因此,对于前置++和后置++,前置- -和后置- -运算符重载,详细讲解前者

4.1 += 和 + 运算符重载

:实现了 += 运算符的重载后,对于 + 运算符的重载就可以利用 += 运算符来实现。

// 日期+=天数
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		if (_month == 12)
		{
			_month = 1;
			_year++;
		}
		else
		{
			_month++;
		}
	}
	return *this;
}
// 日期+天数
Date Date::operator+(int day)
{
	Date temp = *this; // 调用拷贝构造,因为temp不是一个已存在的对象

	temp += day;
	return temp;
}
  • operator+= 的算法思想和步骤:

    1. 输入Date对象的一个引用和一个整数(代表天数)。
    2. 算法思想:将给定的天数加到当前日期的天数上,并相应地调整月份和年份,以确保日期仍然有效。
    3. 步骤
      • 将当前日期的天数(_day)与给定的天数相加。
      • 检查更新后的天数是否超过了当前月份的天数(通过调用GetMonthDay函数)。
      • 如果超过了,从当前月份的天数中减去超出的部分,并更新月份和年份。
        • 如果月份是12月,将月份设置为1月,年份加1。
        • 否则,将月份加1。
      • 返回Date对象的引用,以便进行链式操作。
  • operator+ 的算法思想和步骤:

    1. 输入Date对象的一个实例和一个整数(代表天数)。
    2. 算法思想:创建一个Date对象的副本,并将给定的天数加到副本上,然后返回调整后的日期副本。
    3. 步骤
      • 创建一个Date类型的临时对象temp,并通过拷贝构造函数将其初始化为当前Date对象的副本。
      • 使用operator+=函数将给定的天数加到temp对象上。
      • 返回调整后的temp对象(值拷贝返回)。

:返回Date对象的引用(在operator+=中)允许进行链式操作,如 dateObj += 5 += 3

4.2 -= 和 - 运算符重载
// 日期-天数
Date Date::operator-(int day)
{
	Date temp = *this;

	temp -= day;
	return temp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
	while (day >= _day)
	{
		day -= _day;
		if (_month == 1)
		{
			_month = 12;
			_year--;
			_day = GetMonthDay(_year, _month);
		}
		else
		{
			_month--;
			_day = GetMonthDay(_year, _month);
		}
	}
	_day -= day;
	return *this;
}
4.3 前置++ 和 后置++ 运算符重载
  1. 前置++:返回+1之后的结果

    • 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
  2. 后置++:前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确的重载,C++规定:后置++重载时多增加一个 int 类型的参数,但调用函数时该参数不用传递,编译器自动传递

    • 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将 this 保存一份,然后给 this + 1,而temp是临时对象,因此只能以值的方式返回,不能返回引用。
// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date temp = *this;
	*this += 1;
	return temp;
}
4.4 前置-- 和 后置-- 运算符重载
// 后置--
Date Date::operator--(int)
{
	Date temp = *this;
	*this -= 1;

	return temp;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
4.5 > 和 == 运算符重载

注意:对于比较运算的重载,只要先重载了 > 和 == 运算符,其他运算符的重载就可以利用这两者来实现。

// >运算符重载
bool Date::operator>(const Date& d) const
{
	if (_year > d._year)
		return true;
	else if (_year == d._year)
	{
		if (_month > d._month)
			return true;
		else if (_month == d._month)
		{
			if (_day > d._day)
				return true;
		}
	}
	return false;
}

// ==运算符重载
bool Date::operator==(const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
4.6 >= 、< 、<= 和 != 运算符重载
// >=运算符重载
bool Date::operator >= (const Date& d) const
{
	return *this > d || *this == d;
}
// <运算符重载
bool Date::operator < (const Date& d) const
{
	return !(*this >= d);
}
// <=运算符重载
bool Date::operator <= (const Date& d) const
{
	return !(*this > d);
}
// !=运算符重载
bool Date::operator != (const Date& d) const
{
	return !(*this == d);
}
4.7 日期-日期
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	int flag = 1;
	Date maxDate = *this;
	Date minDate = d;

	if (*this < d)
	{
		flag = -1;
		maxDate = d;
		minDate = *this;
	}

	int n = 0;
	while (maxDate != minDate)
	{
		minDate++;
		n++;
	}
	return flag * n;
}
  • 思路

    1. 比较日期:首先比较当前对象(*this)和传入的日期对象d,确定哪个日期更大,哪个更小。
    2. 确定符号:根据日期的大小关系确定结果的符号。如果当前对象更大,则结果为正;如果传入的日期更大,则结果为负。
    3. 计算天数差从较小的日期开始,逐步增加一天,直到两个日期相等。每次增加一天,就增加计数器的值
    4. 返回结果:根据符号和天数差计算最终的结果,并返回。
  • 步骤

    1. 声明变量
      • flag:用于表示结果的符号,初始化为1(表示正数)。
      • maxDateminDate:用于存储两个日期中较大和较小的日期,初始时分别设置为当前对象(*this)和传入的日期d
    2. 比较日期并确定符号
      • 使用if语句比较*thisd
      • 如果*this小于d,则交换maxDateminDate的值,并将flag设置为-1。
    3. 初始化计数器
      • 声明n并初始化为0,用于计算天数差。
    4. 计算天数差
      • 使用while循环,每次循环将minDate增加一天(即调用minDate++),并增加计数器n的值。
      • 循环继续直到maxDateminDate相等。
    5. 返回结果
      • flagn相乘,得到最终的结果,并返回。
4.8 流插入 << 和 流提取 >> 运算符重载

有了日期类那么我们需要打印日期信息该怎么办呢?

  1. 我们可以实现一个 Print 成员函数来实现:
// 打印,const成员函数修饰的是成员函数隐含的this指针,表明不能修改任何成员变量
void Print() const
{
	cout << _year << "-" << _month << "-" << _day;
}

在这里插入图片描述

但是每次都要调用函数来打印日期是不是太麻烦了,有没有更简单的方法,就像内置类型(int、char等)那样直接使用 cout 打印呢?

  1. 在C++中,对于自定义类型可以重载流插入 << 来实现像内置类型一样的输出操作

在这里插入图片描述
cout 是一个 ostream 类型的对象。

// 流插入<< 重载
ostream& operator<<(ostream& out, const Date& d)
{
	// 输出格式化字符串到输出流  
	out << d._year << "-" << d._month << "-" << d._day << endl;
	// 返回输出流引用以支持链式操作
	return out;
}

在这里插入图片描述

【思路】:

  1. 定义重载函数:定义一个函数,接受一个ostream引用和一个const Date&引用作为参数。
  2. 输出格式化字符串:在函数内部,使用输出流out来格式化并输出Date对象的年、月、日信息。
  3. 返回输出流引用:为了支持链式输出,函数应返回ostream引用

注意事项:

  • 在使用流插入 << 时,要确保第一个参数是ostream的对象,如果是在重载的时候写成成员函数,编译器就会将第一个参数默认传入this指针,因此只能将其重载成全局函数,传入两个参数,第一个为ostream的对象,第二个为Date类对象。
  • 相应的,重载成了全局函数必然会导致类中的私有成员不能被访问,那么这又该如何呢?这里有两种解决办法:
    1. 创建公有的成员函数getYeargetMonthgetDay,这样就可以通过这些函数去访问私有成员变量,java很喜欢使用这种方式。
    2. 使用友元函数,当一个函数或类被声明为另一个类的友元时,它可以访问该类的所有成员,包括私有成员
      在这里插入图片描述

既然有流插入 >> 运算符的重载,那么必然就有流提取 >> 运算符的重载。

  1. 在C++中,对于自定义类型可以重载流提取 >> 来实现像内置类型一样的输入操作

在这里插入图片描述
cin 是一个 istream 类型的对象。

// 流提取 >> 重载
istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请依次输入年 月 日:>";
		in >> d._year >> d._month >> d._day;

		if (!d.CheckInvalid())
		{
			cout << "亲,你输入了无效日期,请重新输入!" << endl;
		}
		else
		{
			break;
		}
	}
	// 返回输入流引用以支持链式操作
	return in;
}

在这里插入图片描述

【思路】

  1. 定义重载函数:定义一个函数,接受一个istream引用和一个Date&引用作为参数。
  2. 输入日期:从输入流中读取年、月、日,并尝试赋值给Date对象。
  3. 验证日期:调用Date对象的CheckInvalid方法来检查输入的日期是否有效。
  4. 错误处理:如果日期无效,则输出错误消息并继续循环,要求用户重新输入。
  5. 返回输入流引用:如果日期有效,则退出循环并返回输入流的引用,以支持链式输入。

5. 日期类源码

5.1 Date.h文件

#pragma once

#include <iostream>

using namespace std;

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month) const;
	// 检查日期是否合法
	bool CheckInvalid();

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;

		if (!CheckInvalid())
		{
			cout << *this << "构造日期非法" << endl;
			exit(-1);
		}
	}

	// 拷贝构造函数
    // d2(d1)
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	// 赋值运算符重载
    // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

	// 析构函数
	~Date()
	{
		//cout << "~Date()" << endl;
	}

	// 取地址操作符重载
	Date* operator&()
	{
		return this;
		//return nullptr;
	}

	// const取地址操作符重载
	const Date* operator&()const
	{
		return this;
		//return nullptr;
	}

	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数

	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();

	// >运算符重载
	bool operator>(const Date& d) const;
	// ==运算符重载
	bool operator==(const Date& d) const;
	// >=运算符重载
	bool operator >= (const Date& d) const;
	// <运算符重载
	bool operator < (const Date& d) const;
	// <=运算符重载
	bool operator <= (const Date& d) const;
	// !=运算符重载
	bool operator != (const Date& d) const;

	// 日期-日期 返回天数
	int operator-(const Date& d);

	// 打印,const成员函数修饰的是成员函数隐含的this指针,表明不能修改任何成员变量
	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	// 友元声明,可以在类的任何位置
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
private:
	int _year;
	int _month;
	int _day;
};

// 类外声明
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

5.2 Date.cpp 文件

#define _CRT_SECURE_NO_WARNINGS 1

#include "Date.h"

// 获取某年某月的天数
int Date::GetMonthDay(int year, int month) const
{
	static int days[13] = { 0,31,28,31,30,31,30,31,30,31,31,30,31 };

	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}

	return days[month];
}

// 日期+=天数
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		if (_month == 12)
		{
			_month = 1;
			_year++;
		}
		else
		{
			_month++;
		}
	}
	return *this;
}
// 日期+天数
Date Date::operator+(int day)
{
	Date temp = *this; // 调用拷贝构造,因为temp不是一个已存在的对象

	temp += day;
	return temp;
}
// 日期-天数
Date Date::operator-(int day)
{
	Date temp = *this;

	temp -= day;
	return temp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
	while (day >= _day)
	{
		day -= _day;
		if (_month == 1)
		{
			_month = 12;
			_year--;
			_day = GetMonthDay(_year, _month);
		}
		else
		{
			_month--;
			_day = GetMonthDay(_year, _month);
		}
	}
	_day -= day;
	return *this;
}

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date temp = *this;
	*this += 1;
	return temp;
}
// 后置--
Date Date::operator--(int)
{
	Date temp = *this;
	*this -= 1;

	return temp;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}

// >运算符重载
bool Date::operator>(const Date& d) const
{
	if (_year > d._year)
		return true;
	else if (_year == d._year)
	{
		if (_month > d._month)
			return true;
		else if (_month == d._month)
		{
			if (_day > d._day)
				return true;
		}
	}
	return false;
}
// ==运算符重载
bool Date::operator==(const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
// >=运算符重载
bool Date::operator >= (const Date& d) const
{
	return *this > d || *this == d;
}
// <运算符重载
bool Date::operator < (const Date& d) const
{
	return !(*this >= d);
}
// <=运算符重载
bool Date::operator <= (const Date& d) const
{
	return !(*this > d);
}
// !=运算符重载
bool Date::operator != (const Date& d) const
{
	return !(*this == d);
}

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	int flag = 1;
	Date maxDate = *this;
	Date minDate = d;

	if (*this < d)
	{
		flag = -1;
		maxDate = d;
		minDate = *this;
	}

	int n = 0;
	while (maxDate != minDate)
	{
		minDate++;
		n++;
	}
	return flag * n;
}

// 检查日期是否合法
bool Date::CheckInvalid()
{
	if (_year <= 0
		|| _month < 1 || _month > 12
		|| _day < 1 || _day > GetMonthDay(_year, _month))
	{
		return false;
	}
	return true;
}

// 流插入 << 重载
ostream& operator<<(ostream& out, const Date& d)
{
	// 输出格式化字符串到输出流  
	out << d._year << "-" << d._month << "-" << d._day << endl;
	// 返回输出流引用以支持链式操作
	return out;
}
// 流提取 >> 重载
istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请依次输入年 月 日:>";
		in >> d._year >> d._month >> d._day;

		if (!d.CheckInvalid())
		{
			cout << "亲,你输入了无效日期,请重新输入!" << endl;
		}
		else
		{
			break;
		}
	}
	// 返回输入流引用以支持链式操作
	return in;
}

总结

🔥💖 此日期类是一个非常适合大家训练自己对运算符重载知识理解和掌握的小项目,它是C++引用传值/传引用返回拷贝构造赋值重载运算符重载const成员函数const修饰参数等知识的一个融合,相信大家在上手练习的过程中能收获颇丰。

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

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

相关文章

【MySQL】数据库的操作(1)

【MySQL】数据库的操作&#xff08;1&#xff09; 目录 【MySQL】数据库的操作&#xff08;1&#xff09;创建数据库数据库的编码集和校验集查看系统默认字符集以及校验规则查看数据库支持的字符集查看数据库支持的字符集校验规则校验规则对数据库的影响数据库的删除 数据库的备…

预算有限,3D渲染更该升级显卡还是CPU?升级电脑配置推荐!

在当今数字化时代&#xff0c;影视、游戏和效果图设计等领域都需要强大的计算机来支持3D渲染工作。受当前国际和市场环境影响&#xff0c;硬件价格持续上涨&#xff0c;有专家预测这种局面将至少持续半年以上。因此&#xff0c;在预算有限的情况下&#xff0c;很多设计师在电脑…

Spring Cloud Gateway核心之Predicate

路由 Predicate 工厂 Spring Cloud Gateway 将路由作为 Spring WebFluxHandlerMapping基础设施的一部分进行匹配。Spring Cloud Gateway 包含许多内置的路由Predicate 工厂。所有这些谓词都匹配 HTTP 请求的不同属性。多个 Route Predicate Factory 可以组合&#xff0c;并通过…

【VTKExamples::PolyData】第四十八期 ShrinkPolyData

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享VTK样例ShrinkPolyData,并解析接口vtkShrinkPolyData,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. ShrinkPol…

基于RFID技术+WMS仓储管理应用设计

一、项目背景 1.1 背景 仓储管理是企业对仓库及其内部物资进行计划、组织、控制和协调的管理过程。它在整个物流和经济活动中扮演着重要的角色&#xff0c;连接着生产者和消费者。 不同规模和产品种类的企业有不同的仓储管理流程和需求&#xff0c;但核心部分都包括仓库作业…

vue+uniapp实现图形验证码功能-插件(附源码)

一、需求背景 vueuniapp实现图形验证码功能-插件&#xff08;附源码&#xff09; 在登录系统时&#xff0c;除了密码登录&#xff0c;还需要提供验证码登录。 涉及验证码&#xff0c;为了安全&#xff0c;一般会加入图形验证码&#xff0c;然后再发短信验证码。 如图&#xff1…

springboot236基于springboot在线课程管理系统的设计与实现

基于SpringBoot在线课程管理系统的设计与实现 摘要 本文首先介绍了在线课程管理系统的现状及开发背景&#xff0c;然后论述了系统的设计目标、系统需求、总体设计方案以及系统的详细设计和实现&#xff0c;最后对在线课程管理系统进行了系统检测并提出了还需要改进的问题。本系…

【QQ案例-QQ框架-静态单元格的使用注意 Objective-C语言】

一、来说一下啊,静态单元格的使用注意 1.静态单元格的使用啊,有一个小的地方,在我们最后一份代码啊,“14-QQ”里面,command + C、command + V、复制一份, 文件名,从“14-QQ副本”,改成“15-静态单元格的注意事项“, 好,然后呢,在这个里边儿,我们点开这个小的项目,…

RWEQ模型高手进阶:土壤风蚀模数估算、制图、归因分析全攻略

土壤侵蚀模型的构建能够更好地探寻侵蚀的原因&#xff0c;以便对土壤侵蚀进行一系列预测工作&#xff0c;减轻其对生态环境的影响。由于侵蚀过程较为复杂&#xff0c;因此建模需要充分考虑各项因素&#xff0c;例如气象、水文、地质环境、土壤条件等。修正的土壤风蚀方程&#…

爬取全国大学排名--数据保存在js文件中的处理办法

网页链接&#xff1a;【软科排名】2023年最新软科中国大学排名|中国最好大学排名 点击xhr后发现数据不存在&#xff0c;在搜索框&#xff08;尽量搜索数字和字母&#xff09;搜索&#xff0c;发现数据在js文件中,这是一个JSONP的格式&#xff0c;相对于json的格式 对js文件进行…

ButterKnife实现之Android注解处理器使用教程

ButterKnife实现之Android注解处理器使用教程 1、新建一个注解 1.1、编译时注解 创建注解所需的元注解Retention包含3个不同的值&#xff0c;RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME。这3个值代表注解不同的保留策略。 使用RetentionPolic…

3月6日

英语 微机原理 硬件中断由 硬件产生 软件中断由软件提供 硬件是随机的 软件是已知的 硬件通常使用类型码 软件是不需要的 硬件的NMI 和 INTR 引脚 无条件 简单外设 查询 CPU效率不高 需要外设提供状态口 中断 需要外设向CPU发送中断请求具有发送中断请求的能力 同时要发送类型…

PandasPython 笔记1 3.5

一般这两个东西相互配合使用 pd.Series 若没有给定行和列的话&#xff0c;就会自动给0&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4 describe 只能描述数字&#xff0c;不可以描述字符串 ascendingfalse&#xff1a;倒序 一般的截取方式 特定的选取方式 有这三…

Vue-04

Vue 指令 指令补充 指令修饰符&#xff1a;通过"."指明一些指令后缀&#xff0c;不同后缀封装了不同的处理操作 → 简化代码 按键修饰符 keyup.enter → 键盘回车监听 在input中使用keyup.enter&#xff0c;这个时候按enter键也能实现添加&#xff0c;和点击按钮实…

(二) 数据库系统的结构抽象与演变

2.1三层模式与两层映像&#xff0c;物理独立性和逻辑独立性 从数据角度可以分为三层视图模式默认指的是全局模式&#xff0c;视图默认指的是外部视图 一个数据库只有一个内模式 DBMS要让用户定义三层模式&#xff0c;程序自动地实现两层映像 。 从外部视图到外模式的数据结构的…

chrome 浏览器只有开启clash 才能上网请求

最近重装了chrome 浏览器&#xff0c;发现只有开着clash才能正常访问网络&#xff0c;关了就无法访问网站。 原因在于浏览器的DNS配置出了问题 现象如下&#xff1a; 出问题的设置&#xff1a; 解决&#xff1a; 把DNS提供商改成系统默认&#xff0c;或者直接把对您访问的网…

网络原理初识(1)

目录 一、网络发展史 1、独立模式 2、网络互联 3、局域网LAN 局域网组建的方式 1、基于网线直连 2、基于集线器组建 3、基于交换机组建 4、基于交换机和路由器组建 4、广域网WAN 二、网络通信基础 1、IP地址 2、端口号 3、认识协议 4、五元组 一、网络发展史 1、独立模式 …

MySQL·SQL优化

目录 一 . 前言 二 . 优化方法 1 . 索引 &#xff08;1&#xff09;数据构造 &#xff08;2&#xff09;单索引 &#xff08;3&#xff09;explain &#xff08;4&#xff09;组合索引 &#xff08;5&#xff09;索引总结 2 . 避免使用select * 3 . 用union all代替u…

Linux第69步_依据“旧字符设备的一般模板”编写LED驱动

在编写LED驱动之前&#xff0c;先要了解和硬件有关的一些知识。 1、了解“MMU内存管理单元”以及相关函数 MMU是Memory Manage Unit的缩写&#xff0c;意思是“内存管理单元”。 老版本的Linux内核要求处理器必须有“MMU内存管理单元”&#xff0c;而现在的Linux内核已经支持…

【Linux】常见指令1(ls指令、pwd指令、cd指令、touch指令、mkdir指令、rmdir指令、man指令、cp指令、mv指令、cat指令)

目录 01.ls指令与ll指令 02.pwd指令 03.cd指令 04.touch指令 05.mkdir指令 06.rmdir指令&&rm指令 07.man指令 08.cp指令 09.mv指令 10.cat指令 01.ls指令与ll指令 ls指令&#xff1a; 原型&#xff1a;list directory contents 语法&#xff1a;ls[选项][目录…