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

在这里插入图片描述

📷 江池俊:个人主页
🔥 个人专栏:✅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.mzph.cn/news/723926.shtml

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

相关文章

JimuReport积木报表 v1.7.1 版本发布,低代码报表工具

项目介绍 一款免费的数据可视化报表&#xff0c;含报表和大屏设计&#xff0c;像搭建积木一样在线设计报表&#xff01;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; Web 版报表设计器&#xff0c;类似于excel操作风格&#xff0c;通过拖拽完成报…

2024年冲刺年薪40w,Android岗面试

一个程序员&#xff0c;如果不想35 岁被淘汰&#xff0c;请把它当成一种信仰&#xff01; 25岁&#xff0c;一个北漂程序员&#xff0c;入职三年&#xff0c;Android中级工程师&#xff0c;月薪15k&#xff0c;965的工作经常干成996&#xff0c;比起老家的同龄人&#xff0c;我…

掘根宝典之C语言文件操作(fgetc,fputc,fscanf,fprintf,fread,fwrite,feek,ftell,fwind,feof)

1. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失 了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进⾏持久…

【C/C++】结构体内存对齐 ----- 面试必考(超详细解析,小白一看就懂!!!)

目录 一、前言 二、引出 ---- 结构体内存对齐 &#x1f34e;结构体偏移量计算&#xff1a;offsetof &#x1f95d;结构体内存对齐详解 &#x1f4a6;规则介绍&#xff08;重点&#xff01;&#xff01;&#xff09; &#x1f4a6;例题解析 三、习题演练 &#x1f34d;练习① …

Spring Cloud 面试题及答案整理,最新面试题

Spring Cloud中断路器的原理及其作用是什么&#xff1f; Spring Cloud断路器的原理和作用基于以下几个关键点&#xff1a; 1、故障隔离机制&#xff1a; 在微服务架构中&#xff0c;断路器作为一种故障隔离机制&#xff0c;当某个服务实例出现问题时&#xff0c;断路器会“断…

Docker知识点总结二

四、 Docker 架构 Docker使用客户端-服务器(C/S)架构模式&#xff0c;使用远程API来管理和创建Docker容器。 介绍&#xff1a; 1、Docker的客户端client&#xff0c;我们在命令行发送一些信息(命令)给Docker服务端。2、中间这个就是Docker的服务端&#xff0c;在这个服务端里面…

漫步者、南卡、Cleer开放式耳机怎么样?硬核对比测评性能强者!

​在当今市场上&#xff0c;开放式耳机的型号层出不穷&#xff0c;作为一名专业的测评博主&#xff0c;我对这类产品有着深入的了解和丰富的经验。最近&#xff0c;我的粉丝们通过私信向我咨询如何选择适合自己的开放式耳机&#xff0c;面对众多品牌的选择&#xff0c;他们感到…

【Unity】使用ScriptableObject存储数据

1.为什么要用ScriptableObject&#xff1f; 在游戏开发中&#xff0c;有大量的配置数据需要存储&#xff0c;这个时候就需要ScriptableObject来存储数据了。 很多人会说我可以用json、xml、txt&#xff0c;excel等等 但是你们有没有想过&#xff0c;假设你使用的是json&#x…

【Linux基础(一)】设备和文件IO

学习分享 1、Linux中的设备管理1.1、设备管理的特点1.2、设备分类1.3、设备工作原理1.4、Linux设备操作1.5、系统调用和系统API等区别 2、文件IO2.1、C库的文件操作2.2、文件描述符2.3、特殊文件描述符2.4、系统调用2.4.1、open系统调用4-12.4.2、open系统调用4-22.4.3、write系…

爬虫实战——伯克利新闻【内附超详细教程,你上你也行】

文章目录 发现宝藏一、 目标二、简单分析网页1. 寻找所有新闻2. 分析模块、版面和文章 三、爬取新闻1. 爬取模块2. 爬取版面3. 爬取文章 四、完整代码五、效果展示 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

2023年扫地机器人行业分析报告(2024年扫地机器人行业未来趋势分析)

当前&#xff0c;随着人们生活水平的提高&#xff0c;扫地机器人因为操作简单、使用方便而越来越多地走入了人们的生活&#xff0c;成为清洁电器中的重要一员&#xff0c;深受消费者欢迎。 伴随科技水平的进步&#xff0c;当前的扫地机器人已经具备了高度智能化的功能&#xf…

C++_位图

目录 1、位图的使用 2、位图实现 3、位图与哈希表的区别 4、位图的应用 结语 前言&#xff1a; 位图采用的是哈希表的思想&#xff0c;哈希表的映射层面是在字节上&#xff0c;而位图的映射层面就是在bit位上。由于bit位所能展现的信息无非只有‘1’和‘0’&#xff0c;所…

【Apple Vision Pro应用源码】Vision Pro吸尘器项目源代码

超级有趣Vision Pro 应用 吸尘器项目 这是一个非常有趣的 Vision Pro项目&#xff0c;会让孩子们爱上打扫卫生。 在这里我展示了如何使用 ARKit&#xff1a;头部跟踪、手部跟踪、场景理解加载和播放声音进程冲突使用 MTLBuffers 处理底层网格数据 项目源代码&#xff1a;Git…

动态规划(算法竞赛、蓝桥杯)--状态压缩DP蒙德里安的梦想

1、B站视频链接&#xff1a;E31 状态压缩DP 蒙德里安的梦想_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; const int N12,M1<<N; bool st[N];//st[i]存储合并列的状态i是否合法 long long f[N][M];//f[i][j]表示摆放第i列&#xff0c;状态为…

java-ssm-jsp-大学社团管理系统

java-ssm-jsp-大学社团管理系统 获取源码——》公主号&#xff1a;计算机专业毕设大全

PSINS工具箱笔记——函数定义

绘图函数&#xff1a; 时间进度条&#xff1a; timebar&#xff08;用起来简单&#xff09; 姿态转换&#xff1a; 欧拉角、姿态矩阵、等效旋转矩阵、姿态四元数、运载火箭使用的欧拉角之间的转换。 轨迹生成&#xff1a; seg trjsegment(seg, segtype, lasting, w, a, var…

centos上部署k8s

环境准备 四台Linux服务器 主机名 IP 角色 k8s-master-94 192.168.0.94 master k8s-node1-95 192.168.0.95 node1 k8s-node2-96 192.168.0.96 node2 habor 192.168.0.77 镜像仓库 三台机器均执行以下命令&#xff1a; 查看centos版本 [rootlocalhost Work]# cat /…

武汉灰京文化:游戏市场推广与用户增长的成功典范

作为游戏行业的明星企业&#xff0c;武汉灰京文化在市场推广和用户增长方面的成功经验备受瞩目。他们以创造性和独特性的市场营销策略&#xff0c;成功吸引了大量用户。这不仅提高了其游戏的知名度&#xff0c;还为公司带来了持续的增长。这一成功模式不仅对公司自身有益&#…

PaddlePaddle----基于paddlehub的OCR识别

Paddlehub介绍 PaddleHub是一个基于PaddlePaddle深度学习框架开发的预训练模型库和工具集&#xff0c;提供了丰富的功能和模型&#xff0c;包括但不限于以下几种&#xff1a; 1.文本相关功能&#xff1a;包括文本分类、情感分析、文本生成、文本相似度计算等预训练模型和工具。…

政安晨【示例演绎虚拟世界开发】(六):从制作一个对战小游戏开始(Cocos Creator 《击败老大》)(第三段)

在上一篇文章中&#xff0c;我们已经将游戏的场景基本搭建完毕&#xff0c;接下来我们就可以为游戏编写代码并实现相关的核心逻辑了。 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: AI虚拟世界大讲堂 希望政安晨的博客能够对您有所裨益&a…