类和对象拓展——日期类

一.前言

通过前面对类和对象的学习,现在我们可以开始实践日期类的代码编写。在实际操作过程中,我会补充之前文章中未提及的相关知识点。

二.正文 

1. 日期类代码实现

我们先来看看要实现什么功能吧,把他放在Date.h中

#pragma once
#include<iostream>
using namespace std;class Date
{
public:// 全缺省的构造函数Date(int year = 2025, int month = 7, int day = 7);void Print(){cout << _year << "-" << _month << "-" << _day << endl;}// 拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}// 运算符重载bool operator<(const Date& x);bool operator==(const Date& x);bool operator<=(const Date& x);bool operator>(const Date& x);bool operator>=(const Date& x);bool operator!=(const Date& x);// 获取某年某月的天数int GetMonthDay(int year, int month);// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day);// 日期-=天数Date& operator-=(int day);// 日期-天数Date operator-(int day);// 日期-日期  返回天数int operator-(const Date& x);// 前置++Date& operator++();// 后置++Date operator++(int);// 前置--Date& operator--();// 后置--Date operator--(int);private:int _year;int _month;int _day;
};

继续像之前一下在准备两个文件,Date.cpp和test.cpp

 1.构造函数

类的对象在创建时会自动调用构造函数,若未显式定义,编译器会生成默认构造函数( Date() ),但默认构造函数不会初始化成员变量。若成员变量未初始化,会出现年月日随机值,会导致对象状态无意义,后续操作必然出错。

Date::Date(int year, int month, int day)
{if (month >= 1 && month <= 12 && day >= 1 && day <= GetMonthDay(year, month)){_year = year;_month = month;_day = day;}else{cout << "非法日期" << endl;}
}

为什么博主选择全缺省参数的构造函数了?

1.构造对象更灵活:支持多种初始化方式 

Date d1;
Date d2(2025);
Date d3(2025, 7);
Date d4(2025, 7, 8);

都可以初始化

2.简化接口设计:减少构造函数重载

非全缺省构造函数需要重载

Date();//无参构造(默认日期)
Date(int year);//仅传年份
Date(int year, int month);//传年份和月份
Date(int year, int month, int day); //全参数构造

而全缺省构造函数只需要一个

3.增强代码可维护性:默认值统一管理

这时候有人好奇了,那析构函数要吗?

不需要的,原因如下:

成员变量无动态资源

存储在栈上或类对象的内存空间中,生命周期结束时会被系统自动释放,无需手动处理。但是当遇到开辟了动态空间,则需要大家自己写析构函数了。 


 2.打印 

为了方便后续的检查代码正确性,写一个打印更方便看到结果。又因为他很简短可以直接放在类里面。

	void Print(){cout << _year << "-" << _month << "-" << _day << endl;}

3.拷贝构造函数 

可以直接写在类里面

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

或者类里面声明,类外面实现如下:

class Date
{
public://省略其他的功能Date(const Date& d);
private:int _year;int _month;int _day;
};Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}

来看看运行结果吧:


4.关系运算符重载 

要写一系列 >  >=  < <= ==  !=关系运算符,我们可以先写一组 < 和 == ,或者 > 和 ==,然后就可以用复用。

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

然后就可以复用了

// <=运算符重载:直接调用上面写的那两个,满足其中一个就好了,所以 ||
bool Date::operator<=(const Date& x)
{return *this < x || *this == x;
}
// < 运算符重载:可直接调用上一个复用
bool Date::operator>(const Date& x)
{return !(*this <= x);
}
// >=运算符重载
bool Date::operator>=(const Date& x)
{return !(*this < x);
}
// !=运算符重载
bool Date::operator!=(const Date& x)
{return !(*this == x);
}

看看运行结果: 


 5.算数运算符

日期加天数

Date& Date::operator+=(int day)
{if (day < 0){return *this -= -day;}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month == 13){_year++;_month = 1;}}return *this;
}
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}

因为可以连续赋值,所以要有返回值,又因为+=改变了本身,所以用Date&,返回*this就好了。 而+不改变本身,所以要先定义一个tmp然后返回tmp。

 +的代码不调用一个为

Date Date::operator+(int day)
{Date tmp(*this);if (day < 0){return tmp - (-day);}tmp._day += day;while (tmp._day > GetMonthDay(tmp._year, tmp._month)){tmp._day -= GetMonthDay(tmp._year, tmp._month);tmp._month++;if (tmp._month == 13){tmp._year++;tmp._month = 1;}}return tmp;
}

为什么是+调用+=而不是+=调用加啦?

1.使用 operator+=  调用 operator+  形成 operator+=  函数

Date& Date::operator+=(int day)
{*this = *this + day;return *this;
}

在 Date& Date::operator+=(int day)  函数中,调用 operator+  时会创建一个临时对象(因为 operator+  通常会返回一个新对象),然后将这个临时对象赋值给 *this 。*this + day  会创建一个临时对象,之后再将其内容复制给当前对象,这就产生了额外的对象创建和销毁开销。建立了两个临时变量

2.使用 operator+  调用 operator+=  形成 operator+  函数

Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}

在 Date Date::operator+(int day)  函数中,仅创建了一个临时对象 tmp ,然后调用 operator+=  直接在这个临时对象上进行日期累加操作。这里只创建了一个 tmp  对象用于存储计算结果。后续不需要再创建额外的临时对象来完成加法操作。

总结:

"使用 operator+ 调用 operator+= 形成 operator+ "函数的方式更好,它能减少临时对象创建、避免多次内存分配与释放、利用编译器优化,提高代码执行效率。


 日期减天数

Date& Date::operator-=(int day)
{if (day < 0){return *this += -day;}_day -= day;while (_day <= 0){--_month;_day += GetMonthDay(_year, _month);if (_month == 0){--_year;_month = 12;}}return *this;
}
Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}

因为可以连续赋值,所以要有返回值,又因为-=改变了本身,所以用Date&,返回*this就好了。 而-不改变本身,所以要先定义一个tmp然后返回tmp。 

  -的代码不调用一个为

Date Date::operator-(int day)
{Date tmp(*this);if (day < 0){return tmp + (-day);}tmp._day -= day;while (tmp._day <= 0){--tmp._month;if (tmp._month == 0){--tmp._year;tmp._month = 12;}tmp._day += GetMonthDay(tmp._year, tmp._month);}return tmp;
}

1.使用 operator-=  调用 operator-  形成 operator-=  函数

Date& Date::operator-=(int day)
{*this = *this - day;return *this;
}

2.使用 operator-  调用 operator-=  形成 operator-  函数

Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}

为什么博主使用"使用 operator- 调用 operator-= 形成 operator- "呢?理由也就是上面一样了。

日期减日期 

int Date::operator-(const Date& x)
{Date min = *this;Date max = x;int flag = 1;if (*this > x){min = x;max = *this;flag = -1;}int dayCount = 0;while (min < max){min++;dayCount++;}return dayCount * flag;
}

这时候有人可能好奇为什么要定义一个flag?

因为如果当前对象(*this)小于x则flag为正,然后乘dayCount则为正,即表示x在当前对象之后,相差dayCount天

而若当前对象比x大则flag为负,然后乘dayCount则为负,即表示当前对象在x之后,相差dayCount天

看看运行结果:  


6.自增自减运算符 

前置++

Date& Date::operator++()
{*this += 1;return *this;
}

 后置++

Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}

前置--

Date& Date::operator--()
{*this -= 1;return *this;
}

后置-- 

Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}

后置++和后置--括号中的int无实际意义只是为了构成重载,易于区分

前置版本( operator++() 、 operator--() ):先加加后使用,先修改当前对象,再返回自身引用( *this )
后置版本( operator++(int) 、 operator--(int) ):先使用后加加,先复制当前对象( tmp ),再修改自身,最后返回修改前的副本。 

运行结果:

上述就是日期类的大致代码,但是我们还能进行优化,让我们继续学习吧。

2.日期类代码的优化

1.const成员 

首先来学习一下const成员

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

因为Print不改变任何成员使用可以加,大家伙可以想想我们上面的日期类代码还有哪里可以加 

若声明和定义分开 ,两个都得写,如下:

我给大家吧要加的写出来

void Print() const
{cout << _year << "-" << _month << "-" << _day << endl;
}bool operator<(const Date& x) const;
bool operator==(const Date& x) const;
bool operator<=(const Date& x) const;
bool operator>(const Date& x) const;
bool operator>=(const Date& x) const;
bool operator!=(const Date& x) const;Date operator+(int day) const;
Date operator-(int day) const;
int operator-(const Date& x) const;

 因为他们不改变任何成员使用可以加。

可能有人好奇为什么要加?又得判断还可能加错。

因为有些使用的人初始化会写成 const Date d2(2025, 11, 22);

使用const是有一定好处的。

只要成员内部不修改成员变量,都应该加const,这样const对象和普通对象都可以调用。权限可以缩小和转移,不能放大。

来看看几题思考题

1. const对象可以调用非const成员函数吗?

不可以。

const对象表示其状态不能被改变。非const成员函数有可能会修改对象的数据成员(因为其没有承诺不修改对象状态),若允许const对象调用非const成员函数,就可能违背const对象不可变的特性。

class MyClass {
public:void nonConstFunc() {data = 10; // 可能修改对象数据成员}
private:int data;
};
const MyClass obj;
obj.nonConstFunc(); // 编译错误,const对象不能调用非const成员函数

2. 非const对象可以调用const成员函数吗?

可以。

const成员函数承诺不会修改对象的数据成员,对于非const对象而言,调用const成员函数不会有违背其可变性的问题,而且这也提供了一种在不同场景下灵活调用函数的方式。

class MyClass {
public:void constFunc() const {// 这里不会修改对象数据成员}
};
MyClass obj;
obj.constFunc(); // 合法,非const对象可以调用const成员函数

3. const成员函数内可以调用其它的非const成员函数吗?

不可以。

const成员函数保证不会修改对象状态,而调用非const成员函数可能会改变对象的数据成员,这就破坏了const成员函数的承诺。

class MyClass {
public:void nonConstFunc() {data = 10;}void constFunc() const {nonConstFunc(); // 编译错误,const成员函数不能调用非const成员函数}
private:int data;
};

4. 非const成员函数内可以调用其它的const成员函数吗? 

可以。

非const成员函数本身就可以修改对象状态,但调用const成员函数不会有问题,因为const成员函数不会改变对象状态,不会破坏非const成员函数对对象状态修改的灵活性 。

class MyClass {
public:void constFunc() const {// 不修改对象数据成员}void nonConstFunc() {constFunc(); // 合法,非const成员函数可以调用const成员函数}
};

总结:

  1. const 对象调用非 const 成员函数:禁止。非 const 成员函数可能修改对象状态,与 const 对象的只读特性相冲突。
  2. 非 const 对象调用 const 成员函数:允许。const 成员函数保证不修改对象状态,与非 const 对象兼容,且可复用只读逻辑。
  3. const 成员函数调用非 const 成员函数:禁止。非 const 成员函数可能修改对象状态,违反 const 成员函数的只读约束。
  4. 非 const 成员函数调用 const 成员函数:允许。非 const 函数可以安全调用只读的 const 函数,既不影响自身逻辑,又能实现代码复用。

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

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。这两个也比较少用。这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容或者不想让人取到普通对象的地址。

1.想让别人获取到指定的内容

class Point {
private:int x, y;
public://下面是初始化列表可以先不要太在意,下一篇会介绍Point(int a, int b):x(a), y(b){}// 取地址时返回x的地址(而非Point对象地址)int* operator&(){return &x;}
};// 使用:
Point p(10, 20);
int* px = &p; // px指向p.x,而非p本身

2.不想让人取到普通对象的地址 

class NoNormalAddr {
public:// 普通对象取地址返回空NoNormalAddr* operator&(){return nullptr;}const NoNormalAddr* operator&() const{return this;}
};// 使用:
NoNormalAddr obj;
const NoNormalAddr c_obj;
&obj; // 得到nullptr
&c_obj; // 得到实际地址

可能有人那代码去VS中尝试了,发现会红为什么了?

简单说:取地址操作本身不报错,但返回的 nullptr  是无效地址,用它做后续操作时才会因“访问无效内存”而报错。这是一种通过返回无效结果间接阻止滥用地址的方式。


3.流插入和流提取 

先来看看这个图片简单了解一下

流插入<< 

先看看我们用operator的常规思想 

void Date::operator<<(ostream& out)
{out << _year << "-" << _month << "-" << _day << endl;
}void test7()
{Date d1(2025, 1, 25);d1 << cout;//d1.operator<<(cout);
}

发现调用的时候不符合我们常规调用,因为成员函数第一个参数是隐藏的this,使用调用就成这样了。为了正常,我们要将他写在全局,这样this就不占用参数了。且我们还可能连续插入,修改后的:

糟糕爆红了,发现_year,_month,_day 位于私有调用不到怎么办了?

方法一:友元函数,在类里面加入

friend ostream& operator<<(ostream& out, const Date& d);

此时就可以调用了,调用结果:

此时就符合习惯了。

友元

我们来学一下友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用

友元分为:友元函数和友元类

 友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字

//frinnd+函数名
friend ostream& operator<<(ostream& out, const Date& d);

注意:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

class Time
{friend class Date;// 声明日期类为时间类的友元类,// 则在日期类中就直接访问Time类中的私有成员变量
public:...;//博主懒了
private:int _hour;int _minute;int _second;
};class Date
{
public:...;//博主懒了void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}
private:int _year;int _month;int _day;Time _t;
};

注意:

  • 友元关系是单向的,不具有交换性。 比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time 类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  • 友元关系不能传递。如果B是A的友元,C是B的友元,则不能说明C时A的友元。
  • 友元关系不能继承,在继承位置再给大家详细介绍。

 方法二:定义一个函数用来获取_year,_month,_day

//写在类里面
int GetYear() const
{return _year;
}int GetMonth() const
{return _month;
}int GetDay() const
{return _day;
}

流提取>>

 按照上面的学习:

//类里面
friend istream& operator>>(istream& cin, Date& d);istream& operator>>(istream& in, Date& d)
{int year, month, day;in >> year >> month >> day;if (month > 0 && month < 13&& day > 0 && day <= d.GetMonthDay(year, month)){d._year = year;d._month = month;d._day = day;}else{cout << "非法日期" << endl;assert(false);}return in;
}

 为什么没const了?

因为两个都要修改。流提取要改变里面的状态值,使用不用。

调用结果:

三.总结

希望这个日期类的知识能对你有所帮助!如果觉得实用,欢迎点赞支持~ 要是发现任何问题或有改进建议,也请随时告诉我。感谢阅读!

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

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

相关文章

大模型KV缓存量化误差补偿机制:提升推理效率的关键技术

大模型KV缓存量化误差补偿机制&#xff1a;提升推理效率的关键技术摘要 随着大型语言模型&#xff08;LLM&#xff09;参数规模突破千亿级别&#xff0c;推理过程中的显存占用与计算延迟成为制约其实际部署的核心瓶颈。KV缓存&#xff08;Key-Value Cache&#xff09;作为Trans…

QT跨平台应用程序开发框架(6)—— 常用显示类控件

目录 一&#xff0c;Label 1.1 主要属性 1.2 文本格式 1.3 设置图片 1.4 其它常用属性 1.5 设置伙伴 二&#xff0c;LCD Number 2.1 主要属性 2.2 实现倒计时 ​2.3 两个问题 三&#xff0c;ProgressBar 3.1 主要属性 3.2 进度条按时间增长 3.3 改变样式 3.4 一个问题 四&#…

LINUX文件系统权限,命令解释器alias,文件查看和查找

1、文件査看:查看/etc/passwd文件的第5行[rootserver ~]# head -5 /etc/passwd | tail -1 #先找到前5行&#xff0c;用管道符过滤&#xff0c;显示倒数第一行2、文件查找(1)在当前目录及子目录中&#xff0c;查找大写字母开头的txt文件[rootserver ~]# find / -name "[…

AI图像修复工具CodeFormer实测:马赛克去除与画质增强效果评测

大家好&#xff01;平时看图片或视频&#xff0c;是不是特别烦人脸被马赛克遮住的地方&#xff1f;比如老照片模糊、视频关键部分被打码&#xff0c;看着很不舒服。今天给大家分享一款超好用的去马赛克神器——CodeFormer&#xff0c;完全免费&#xff0c;新手也能轻松搞定&…

知识宇宙-思考篇:AI大模型如何重塑软件开发流程?

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录AI大模型重塑软件开发&#xff1a;从码农到AI编程伙伴的华丽转身一、AI大模型的编程&…

Rocky Linux上使用NVM安装Node.js 18

问题描述 Rocky Linux 9 默认 yum 安装的 Node.js 版本是16&#xff0c;vite启动报错&#xff1a;TypeError: crypto$2.getRandomValues is not a function &#xff0c;需安装更高版本的 Node.js 使用nvm安装Node.js的好处 多版本管理&#xff0c;NVM 允许你安装多个不同版本的…

JVM 中“对象存活判定方法”全面解析

1. 前言 在 Java 开发过程中&#xff0c;我们常常听到“垃圾回收”&#xff08;Garbage Collection, GC&#xff09;这一术语。JVM 通过垃圾回收机制自动管理内存&#xff0c;极大地简化了程序员的内存控制负担。然而&#xff0c;GC 究竟是如何判断哪些对象该回收、哪些应保留…

苹果公司高ROE分析

公司通过增加负债提升净资产收益率&#xff08;ROE&#xff09;的核心机制在于财务杠杆效应和资本结构优化&#xff0c;以下从原理、操作路径、风险边界及苹果案例四维度展开分析&#xff1a;名称解释&#xff1a; ROIC(投入资本回报率)&#xff1a;ROICNOPATInvested Capital …

【Linux系统】进程概念

1. 进程概念1.1 进程的本质核心定义用户视角&#xff1a;程序的动态执行实例&#xff08;如同时运行多个Chrome窗口即多个进程&#xff09;。内核视角&#xff1a;资源分配的最小实体单位&#xff0c;独享CPU时间片、内存空间和文件资源。现代定义&#xff1a;进程 内核数据结…

从LLM到VLM:视觉语言模型的核心技术与Python实现

本教程的完整代码可以在GitHub上找到&#xff0c;如果你有任何问题或建议&#xff0c;欢迎交流讨论。 引言&#xff1a;为什么需要VLM&#xff1f; 当我们与ChatGPT对话时&#xff0c;它能够理解复杂的文字描述&#xff0c;生成流畅的回答。但如果我们给它一张图片&#xff0c…

老系统改造增加初始化,自动化数据源配置(tomcat+jsp+springmvc)

老系统改造增加初始化&#xff0c;自动化数据源配置一、前言二、改造描述1、环境说明2、实现步骤简要思考三、开始改造1、准备sql初始化文件2、启动时自动读取jdbc文件&#xff0c;创建数据源&#xff0c;如未配置&#xff0c;需要一个默认的临时数据源2.1去掉sping mvc原本配置…

卫星通信终端天线的5种对星模式之二:DVB跟踪

要实现稳定可靠的卫星通信&#xff0c;地面终端天线必须精准地对准远方的卫星。对星的过程是一个不断搜索、不断逼近的过程&#xff0c;其目标是让天线波束中心精确指向卫星&#xff0c;从而获得最大信号接收与发射效率。 卫星通信终端天线的对星技术是保障卫星通信链路稳定的…

重构下一代智能电池“神经中枢”:GCKontrol定义高性能BMS系统级设计标杆

概述BMS&#xff08;电池管理系统&#xff09;作为新能源汽车动力电池与整车的核心纽带&#xff0c;通过实时监控电压、电流、温度及SOC等参数&#xff0c;控制电池充放电过程&#xff0c;保障电池安全性与使用寿命。随着电动汽车智能化发展&#xff0c;对BMS的响应速度、精度和…

面试150 对称二叉树

思路 联想递归三部曲&#xff1a;传入参数、遍历方式、返回什么。本题联想到先序遍历的方式,需要遍历整颗二叉树,最后返回的是一个布尔值。然后我们需要传入的是左子树和左子树的节点,然后分别进行比较。 # Definition for a binary tree node. # class TreeNode: # def __…

多线程的区别和联系

进程和线程的区别和联系1.一个进程可以包含多个线程&#xff0c;不能够没有线程2.进程是系统资源分配的基本单位&#xff0c;线程是系统调度执行的基本单位3.同一个进程里的线程之间&#xff0c;共用同一份系统资源4.线程是当下实现并发编程的主流方式&#xff0c;通过多线程&a…

两个文件夹自动同步

两个文件夹自动同步&#xff0c;非常简单&#xff0c;利用一些工具就可以轻松做到&#xff0c;设置完源和目标文件夹&#xff0c;点击启动就马上可以两个文件夹自动同步&#xff0c;对于一些有文件同步、文件灾备需求的老登&#xff0c;用起来会非常顺手&#xff0c;比如PanguF…

虚拟商品交易维权指南:数字经济时代的消费者权益保护

首席数据官高鹏律师数字经济团队创作AI辅助在元宇宙、NFT、虚拟情绪产品等新兴领域蓬勃发展的今天&#xff0c;虚拟商品交易已成为数字经济的重要组成部分。从游戏皮肤、在线课程到数字藏品&#xff0c;消费者在享受虚拟商品便捷性的同时&#xff0c;也面临着诸多法律风险。作为…

mysql 一条语句的执行流程

文章目录一条查询语句的执行流程连接器管理连接权限校验分析器优化器采样统计优化器选错索引改正执行器查询缓存存储引擎一条update语句的执行流程redo logredo log buffer结构redo log日志类型写入时机配置innodb_flush_log_at_trx_commitbinlogredo log和binlog 对比配置两阶…

【视频观看系统】- 需求分析

&#x1f3af; 一、项目目标 构建一个功能完备的视频观看网站&#xff0c;用户可以上传、浏览、观看视频&#xff0c;并在观看过程中实时发送/接收弹幕。系统具备良好的性能、可扩展性与用户体验&#xff0c;未来可逐步扩展为多媒体平台。&#x1f464; 二、用户角色分析用户类…

模型驱动的架构MDA的案例

在一个企业资源规划&#xff08;ERP&#xff09;系统开发项目中&#xff0c;目标是为一家中型制造企业打造一套高效且可扩展的管理系统&#xff0c;涵盖订单处理、库存管理等多个业务模块。项目团队采用了 MDA 的设计思想进行开发。​首先是业务需求分析与计算独立模型&#xf…