C++——类和对象之运算符重载
运算符重载
本章思维导图:
注:本章思维导图对应的xmind
文件和.png
文件都已同步导入至”资源“
文章目录
- 运算符重载
- @[toc]
- 1. 运算符重载的意义
- 2. 函数的声明
- 2.1 声明运算符重载的注意事项
- 3. 函数的调用
- 4. const成员函数
- 4.1 const成员函数的声明
- 4.2 注意点
- 5. 两个默认成员函数
- 5.1 赋值运算符重载
- 5.1.1 函数的声明
- 5.1.2 函数的定义
- 5.1.3 赋值运算符重载和拷贝构造的区别
- 5.1.4 默认赋值运算符重载
- 5.2 &和const &运算符重载
- 6. 流插入<<、流提取>>运算符重载
- 6.1 函数的声明
- 7. Date类的实现
- 7.1 对于部分代码的说明
文章目录
- 运算符重载
- @[toc]
- 1. 运算符重载的意义
- 2. 函数的声明
- 2.1 声明运算符重载的注意事项
- 3. 函数的调用
- 4. const成员函数
- 4.1 const成员函数的声明
- 4.2 注意点
- 5. 两个默认成员函数
- 5.1 赋值运算符重载
- 5.1.1 函数的声明
- 5.1.2 函数的定义
- 5.1.3 赋值运算符重载和拷贝构造的区别
- 5.1.4 默认赋值运算符重载
- 5.2 &和const &运算符重载
- 6. 流插入<<、流提取>>运算符重载
- 6.1 函数的声明
- 7. Date类的实现
- 7.1 对于部分代码的说明
1. 运算符重载的意义
我们都知道,对于内置类型我们是可以直接用运算符直接对其进行操作的,但是对于自定义类型,这种做法是不被允许的。
例如对于Date
类:
Date d1;
Date d2(2023, 11, 3);d1 == d2;
//会报错:error C2676: 二进制“==”:“Date”不定义该运算符或到预定义运算符可接收的类型的转换
因此,为了解决自定义类型不能使用操作符的问题,C++就有了运算符重载
2. 函数的声明
一般来说,运算符重载的函数最好声明在类里面,这样就可以使用被private
修饰的成员变量
声明方式:
operator 运算符 形参列表
- 函数的返回值应该和运算符的意义相对应。例如对于比较运算符
>、==
就应该返回bool
值,对于+、-
就应该返回当前类类型- 函数的形参个数应该和运算符的操作数相对应
例如,我们要声明定义一个Date += 整数
的函数,那我们就要重载运算符+=
:
//根据+=运算符的意义,其返回值应该是操作数本身,因此返回其引用
Date& operator +=(int day)
{//仅作为运算符重载如何声明定义的演示//实现细节先不做说明return *this;
}
2.1 声明运算符重载的注意事项
有小伙伴可能注意到:为什么Date& operator +=(int day)
的形参只有一个day
,不是说形参个数要和运算符的操作数对应吗?
我们不能忘记:在类的成员函数中,都有一个默认的形参this
指针来指向当前的对象。
同时还应该注意以下几点:
- 不能通过连接其他符号来实现重载,例如
operator @()
是不被允许的- 不能修改内置类型运算符的意义
.* . :? sizeof ::
这五个运算符是不可以重载的- 对于二元运算符(操作数为2的运算符),形参列表的第一个参数为左操作数,第二个参数为右操作数。因此对于声明在类里面的重载函数,
this
指针永远是左操作数
3. 函数的调用
在声明定义好运算符重载后,有两种调用方法:
第一种——像内置类型一样直接使用运算符:
d1 += 10;
//调用Date& operator +=(int day)函数,在对象d1的基础上加10
第二种——像调用函数一样,使用运算符重载:
d1.operator+=(10);
//调用Date& operator +=(int day)函数,在对象d1的基础上加10
4. const成员函数
我们来看下面的代码:
class Date
{
public:Date(int year = 2023, int month = 11, int day = 3){//简单的值拷贝_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << _year << ';' << _month << ' ' << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;const Date d2;d1.Print(); //Yesd2.Print(); //Notreturn 0;
}
//d2.Print()会报错:不能将“this”指针从“const Date”转换为“Date &”
这是因为:
我们之前提到过,引用不能涉及到权限的放大,
const Date d2
对应的是const Date* this
,而函数Date* this
,这就涉及到了权限的放大。
因此,为了解决被const
修饰的对像不能调用成员函数的问题,我们可以用const
来修饰成员函数,这样,本质上成员函数的this
指针就被const修饰了,从而也就可以被const
对象调用。
4.1 const成员函数的声明
将一个成员函数变为
const
成员函数,只要在该函数声明的最后加上const
修饰符即可
例如对于上面提到的Pinrt()
成员函数,将其变为const
成员函数即:
void Print() const
{cout << _year << ';' << _month << ' ' << _day << endl;
}
4.2 注意点
应该知道,引用不能涉及权限的放大,但是可以进行权限的平移和缩小。
因此:
const
对象可以调用const
成员函数非const
对象也可以调用const
成员函数
但并不能说可以将所有的成员函数都声明为const
成员函数,因为对于有些成员函数,它需要在函数内部修改对象的成员变量。
但是对于那些不需要修改对象成员变量的成员函数,建议都将其声明为cosnt
,这样const
对象和非const
对象都能调用
5. 两个默认成员函数
运算符重载中也有两个成员函数,分别是:赋值=
运算符重载和取地址&\const &
运算符重载
5.1 赋值运算符重载
赋值运算符重载是类的默认成员函数
5.1.1 函数的声明
- 因为赋值运算符重载是类的默认成员函数,因此必须声明在类的里面
=
运算符的操作对象为2,因此该函数有两个形参。第一个形参为被隐藏的this
指针,第二个形参就是要赋予值的对象,且该对象最好被const修饰- 为了支持连续赋值,函数的返回值应该是类类型的引用
例如,声明一个Date
类的赋值运算符重载:
Date& operator=(const Date& d)
{//
}
5.1.2 函数的定义
应该清楚,赋值实际上也是一种拷贝。而拷贝又分为深拷贝和浅拷贝:
浅拷贝:
- 浅拷贝又称值拷贝
- 浅拷贝只是对成员变量值的简单复制,而不是复制指向的动态分配的资源(如堆内存)
- 原对象和拷贝对象将共享相同的资源。
深拷贝:
- 深拷贝又称址拷贝
- 相较于浅拷贝只是对成员变量值的简单赋值,深拷贝会复制对象的成员变量以及指向的资源,包括指针指向的数据
- 这确保了原对象和拷贝对象拥有彼此独立但内容相同的资源副本。
关于深浅拷贝更为清楚的解释请移步👉C++——拷贝构造
既然拷贝分为深浅拷贝,那么我们的赋值运算符重载也应该分为值拷贝、址拷贝
这两种情况:
值拷贝:
例如对于
Date
类,里面没有指针指向空间资源,因此只需要对其成员变量进行简单复制操作Date& operator=(const Date& d) {//简单的值拷贝_year = d._year;_month = d._month;_day = d._day;return *this; }
址拷贝:
例如对于
Stack
类,里面有一个指针用于指向栈存储的空间,因此需要进行深拷贝来创建一个和源对象内容相同但地址不同的空间Stack& operator=(const Stack& st) {_capacity = st._capacity;_top = st._top;//深拷贝_a = (int*)malloc(sizeof(int) * _capacity);if (nullptr == _a){perror("malloc");exit(-1);}memcpy(_a, st._a, sizeof(int) * _capacity);return *this; }
5.1.3 赋值运算符重载和拷贝构造的区别
看完上面函数的定义,有小伙伴就肯定会有疑惑了:
这看起来二者之间没有什么区别嘛,为什么要做区分?
我们来看下面的例子:
class Date
{
public://构造Date(int year = 2023, int month = 11, int day = 3){_year = year;_month = month;_day = day;}//拷贝构造Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//赋值运算符重载Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2 = d1; //拷贝构造还是赋值运算符重载???Date d3;d3 = d2; //拷贝构造还是赋值运算符重载???return 0;
}
各位认为,上面问题的答案是什么?让我们来进行调试:
可以得出结论:赋值运算符重载和拷贝构造的不同之处在于:
- 拷贝构造注重的是
构造
,即用一个已经存在的对象来实例化构造一个新的对象- 赋值运算符重载注重的是
赋值
,即对两个已经存在的对象进行赋值操作
5.1.4 默认赋值运算符重载
和其他默认成员函数一样,如果自己没有声明和定义赋值运算符重载,编译器会自动生成一个
和拷贝构造一样,默认运算符重载只会对成员变量进行简单的值拷贝(浅拷贝),因此如果类的成员变量有指向内存空间的指针,仅依赖系统默认生成的赋值运算符重载是不够的,需要自己声明定义,来实现深拷贝
5.2 &和const &运算符重载
这两个函数都是类的默认成员函数
- 他们的作用仅用于返回对象的地址
Date* operator&()
{return this;
}const Date* operator&() const
{return this;
}
这两个默认成员函数一般用编译器自动生成的默认&
运算符重载即可,不需要自己声明和定义
6. 流插入<<、流提取>>运算符重载
通过查阅资料我们可以得知:cout
是ostream
类的对象,cin
是istream
类的对象
extern ostream cout;
extern istream cin;
6.1 函数的声明
我们可以先看一个例子来推出这两个重载函数的返回值是什么:
cout << 10 << 20;
这串代码实现的是向屏幕连续输出两个数字
10和20
,<<
运算符的运算顺序应该是从左到右,而为了能够实现连续的cout
,我们可以假象在执行完cout << 10
后有生成了一个cout
来完成cout << 20
而为了能够实现执行完cout << 10
后又生成一个cout
,cout
运算符重载的返回值就应该是ostream
类的引用,即ostream &
同理,cin
运算符重载的返回值就应该是istream &
接下来的问题是,这两个运算符重载应该放在类里面还是类外面呢?
如果声明在类里面:
class Date { public://构造Date(int year = 2023, int month = 11, int day = 3){_year = year;_month = month;_day = day;}ostream& operator<<(ostream& _cout){_cout << _year << ' ' << _month << ' ' << _day << endl;return _cout;} private:int _year;int _month;int _day; };
那当我们使用时:
int main() {Date d1;cout << d1;return 0; } //就会报错:二元“<<”: 没有找到接受“Date”类型的右操作数的运算符(或没有可接受的转换)
这是因为,我们在前面就说过,对于二元运算符,第一个形参就是左操作数,第二个形参就是右操作数。而对于类的成员函数,
this
指针就是第一个参数,即左操作数。因此对于流插入运算符<<
,左操作数就是d1
,右操作数就是_cout
。正确的写法应该为:
d1 << cout;
显然,这种写法的可读性是极差的。我们**应该想办法使
_cout
成为左操作数,this
指针成为右操作数,**但是对于类的成员函数,形参的第一个都必定是指向对象的this
指针,所以,为了达到要求,我们应该将<<
和>>
运算符的重载声明定义在类的外面即:
class Date { public://构造Date(int year = 2023, int month = 11, int day = 3){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day; };ostream& operator<<(ostream& _cout, const Date& d) {_cout << d._year << ' ' << d._month << ' ' << d._day << endl;return _cout; }
我们将<<
和>>
运算符的重载声明在类外面,可读性的问题是解决了,但是这样就访问不了被private
修饰的成员变量了呀。
为了解决这个问题,我们可以使用友元函数friend
将非类成员函数的函数声明放在类里面,再在声明前面加上修饰符
friend
,这样这个函数就变成了友元函数。
- 友元函数不是类的成员函数
- 但是可以直接访问类的私有成员
例如,对于上面的代码:
class Date
{
public://构造Date(int year = 2023, int month = 11, int day = 3){_year = year;_month = month;_day = day;}friend ostream& operator<<(ostream& _cout, const Date& d);private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << ' ' << d._month << ' ' << d._day << endl;return _cout;
}
这样,我们就可以正确使用<<
和>>
运算符重载了。
7. Date类的实现
class Date
{
public:// 获取某年某月的天数int GetMonthDay(int year, int month){int nums[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };if (month == 2 && (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)))return nums[month] + 1;elsereturn nums[month];}// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1){if (year < 1 || month < 1 || month > 12 || day < 1 || day > GetMonthDay(year, month)){cout << "输入非法" << endl;exit(-1);}_year = year;_month = month;_day = day;}// 拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}// 赋值运算符重载Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}// 日期+=天数Date& operator+=(int day){if (day < 0){return *this -= (-day);}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_month = 1;_year++;}}return *this;}// 日期+天数Date operator+(int day){Date tmp = *this;tmp += day;return tmp;}// 日期-天数Date operator-(int day){ Date tmp = *this;tmp -= day;return tmp;}// 日期-=天数Date& operator-=(int day){if (day < 0)return *this += (-day);_day -= day;while (_day < 1){_month--;if (_month <= 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return *this;}// 前置++Date& operator++(){*this += 1;return *this;}// 后置++Date operator++(int){Date tmp = *this;*this += 1;return tmp;}// 后置--Date operator--(int){Date tmp = *this;*this -= 1;return tmp;}// 前置--Date& operator--(){*this -= 1;return *this;}// >运算符重载bool operator>(const Date& d){if (_year > d._year)return true;else if (_year == d._year && _month > d._month)return true;else if (_year == d._year && _month == d._month && _day > d._day)return true;elsereturn false;}// ==运算符重载bool operator==(const Date& d){return _year == d._year && _month == d._month && _day == d._day;}// >=运算符重载bool operator >= (const Date& d){return (*this == d) || (*this > d);}// <运算符重载bool operator < (const Date& d){ return !(*this >= d);}// <=运算符重载bool operator <= (const Date& d){return (*this == d) || (*this < d);}// !=运算符重载bool operator != (const Date& d){return !(*this == d);}// 日期-日期 返回天数int operator-(const Date& d){int flag = 1;if (!(*this >= d))flag = -1;Date cmp_big = *this >= d ? *this : d;Date cmp_small = *this < d ? *this : d;int count = 0;while (cmp_big != cmp_small){count++;++cmp_small;}return flag * count;}// 析构函数~Date(){//cout << "~Date()" << endl;}private:int _year;int _month;int _day;
};
7.1 对于部分代码的说明
-
注意代码的复用,这样可以少些许多代码,提高效率。
例如:定义好
+=、-=
的运算符重载后,-、+
运算符的重载就可以复用+=、-=
的代码;定义好==、>
的运算符重载后,其他比较运算符就可以复用==、>
的运算符重载来实现,从而大幅减少了代码量。 -
注意前置
++
和后置++
的运算符重载(前置--
和后置--
同理)由于C++规定,要构成运算符重载,运算符必须跟在
operator
后,因此当碰到前置++和后置++这种运算符相同(函数名相同)但函数实现的功能不同的情况时,就需要利用函数重载。我们可以在后置++
的运算符重载函数的形参列表里加入一个形参,和前置++
构成函数重载,这样就可以避免问题了。
相关文章:

C++——类和对象之运算符重载
运算符重载 本章思维导图: 注:本章思维导图对应的xmind文件和.png文件都已同步导入至”资源“ 文章目录 运算符重载[toc] 1. 运算符重载的意义2. 函数的声明2.1 声明运算符重载的注意事项 3. 函数的调用4. const成员函数4.1 const成员函数的声明4.2 注意…...

第二阶段第一章——面向对象
前言 学习了这么久Python(呃其实也没多久差不多两周),可能有小伙伴说我废了,两周才学这么点,咋说呢,我曾经也是急于求成,做任何事情都是急于求成,比如我喜欢一个人我就想马上跟她在…...

Linux学习第33天:Linux INPUT 子系统实验(二):Linux 自带按键驱动程序的使用
Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本节笔记主要内容是学会如何使用Linux自带的按键驱动程序。 一、自带按键驱动程序源码简析 配置选项路径如下: -> Device Drivers ->…...

解决Visual Studio 2010 运行时屏幕一闪而过,无结果显示的问题
安装配置:Visual Studio 2010 软件安装教程(附下载链接)——计算机二级专用编程软件https://blog.csdn.net/W_Fe5/article/details/134218817?spm1001.2014.3001.5502 1、 我们在运行时会出现窗口一闪而过,这时候我们右键Test_1…...

C++(20):为[[nodiscard]]提供提示信息
C17中引入了[[nodiscard]]以对一些被忽略的函数返回值进行警告。 C(17):[[nodiscard]]编译属性_[[nodiscard]] c-CSDN博客 C20可以为[[nodiscard]]提供一个可选的提示信息 [[nodiscard("cant ignore")]] int fi() {return 1; }int main() {fi();return 0…...

hi3518ev200 从sd卡启动rootfs
板卡为 hisi 的 hi3518ev200,16M RAM,64M Flash。板卡不支持从SD卡启动,但是由于Flash空间有限,很多应用都放不下,因此考虑把 rootfs 放到 SD 卡中。先从 Flash 中启动 kernel,然后再加载 SD 卡中的 rootfs…...

[BUUCTF NewStar 2023] week5 Crypto/pwn
最后一周几个有难度的题 Crypto last_signin 也是个板子题,不过有些人存的板子没到,所以感觉有难度,毕竟这板子也不是咱自己能写出来的。 给了部分p, p是1024位给了922-101位差两头。 from Crypto.Util.number import * flag b?e 655…...

使用seldom编写http接口用例
在编写接口用例的过程中,针对一个接口,往往只是参数不同,那么参数化就非常有必要了。 seldom 中参数化的用法非常灵活,这里仅介绍file_data() 的N种玩法。 二维列表 当参数比较简单时可以试试下面的方式。 参数化数据 {"…...

Redis中Hash类型的命令
目录 哈希类型的命令 hset hget hexists hdel hkeys hvals hgetall hmget hlen hsetnx hincrby hincrbyfloat 内部编码 Hash类型的应用场景 作为缓存 哈希类型和关系型数据库的两点不同之处 缓存方式对比 Redis自身已经是键值对的结构了,Redis自身的键值对就…...

Java 函数式编程
1.Lambda 1.1 格式 JDK 从 1.8 版本开始支持 Lambda 表达式,通过 Lambda 表达式我们可以将一个函数作为参数传入方法中。在 JDK 1.8 之前,我们只能通过匿名表达式来完成类似的功能,但是匿名表达式比较繁琐,存在大量的模板代码&…...

类的成员函数总结
前言: 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。 默认成员函数:用户没有显式实现,编译器会生成的…...

java高级之单元测试、反射
1、Junit测试工具 Test定义测试方法 1.被BeforeClass标记的方法,执行在所有方法之前 2.被AfterCalss标记的方法,执行在所有方法之后 3.被Before标记的方法,执行在每一个Test方法之前 4.被After标记的方法,执行在每一个Test方法之后 public …...

MSQL系列(十三) Mysql实战-left/right/inner join 使用详解及索引优化
Mysql实战-left/right/inner join 使用详解及索引优化 前面我们讲解了BTree的索引结构,也详细讲解下Join的底层驱动表 选择原理,今天我们来了解一下为什么会出现内连接外连接,两种连接方式,另外实战一下内连接和几种最常用的join…...

前端面试题之HTML篇
1、src 和 href 的区别 具有src的标签有:script、img、iframe 具有href的标签有:link、a 区别 src 是source的缩写。表示源的意思,指向资源的地址并下载应用到文档中。会阻塞文档的渲染,也就是为什么js脚本放在底部而不是头部的…...

Django ORM:数据库操作的Python化艺术
Django的对象关系映射器(ORM)是其核心功能之一,允许开发者使用Python代码来定义、操作和查询数据库。这篇文章将带你深入了解Django ORM的强大之处,从基本概念到高级查询技巧,提供丰富的示例帮助你掌握使用Django ORM进…...

react受控组件与非受控组件
React中的组件可以分为受控组件和非受控组件: 受控组件:受控组件是指组件的值受到React组件状态的控制。通常在组件中,我们会通过state来存储组件的值,然后再将state的值传递给组件的props,从而实现组件的双向数据绑定…...

小米产品面试题:淘宝为何需要确认收货?京东为何不需要?
亲爱的小米粉丝们,大家好!我是小米,一个热爱技术、热衷于分享的小编。今天,我要和大家聊聊一个有趣的话题:为什么淘宝购物需要确认收货,而京东不需要?这可是一个让很多人纳闷的问题,…...

(1)上位机底部栏 UI如何设置
上位机如果像设置个多页面切换: 位置: 代码如下: "tabBar": {"color": "black","selectedColor": "#d43c33","borderStyle":"black","backgroundColor": …...

中国多主数据库:压强投入,期待破茧
拿破仑曾说:“战争的艺术就是在某一点上集中最大优势兵力”,强调了力量集中的重要性。 如今,国际形势风云变幻,西方世界对中国的围剿不再仅仅体现在军事和地缘政治上,而更多表现在经济与科技上。在科技领域࿰…...

JavaScript在ES6及后续新增的常用新特性
JavaScript经历了不同标本的迭代,在不断完善中会添加不同的新特性来解决前一个阶段的瑕疵,让我们开发更加便捷与写法更加简洁! 1、箭头函数: 箭头函数相比传统的函数语法,具有更简洁的语法、没有自己的this值、不会绑…...

试试流量回放,不用人工写自动化测试case了
大家好,我是洋子,接触过接口自动化测试的同学都知道,我们一般要基于某种自动化测试框架,编写自动化case,编写自动化case的依据来源于接口文档,对照接口文档里面的请求参数进行人工添加接口自动化case 其实…...

密钥管理系统功能及作用简介 安当加密
密钥管理系统的功能主要包括密钥生成、密钥注入、密钥备份、密钥恢复、密钥更新、密钥导出和服务,以及密钥的销毁等。 密钥生成:通过输入一到多组的密钥种子,按照可再现或不可再现的模式生成所需要的密钥。一般采用不可再现模式作为密钥生成…...

vue中watch属性的用法
在Vue中,watch属性用于监听一个数据的变化,并且在数据变化时执行一些操作。它可以观察一个具体的数据对象,从而在该数据对象发生变化时触发对应的回调函数。 使用watch属性的步骤如下: 在Vue实例中添加一个watch对象 new Vue({…...

Redis-使用java代码操作Redis
🏅我是默,一个在CSDN分享笔记的博主。📚📚 🌟在这里,我要推荐给大家我的专栏《Linux》。🎯🎯 🚀无论你是编程小白,还是有一定基础的程序员,这…...

0基础学习PyFlink——事件时间和运行时间的窗口
大纲 定制策略运行策略Reduce完整代码滑动窗口案例参考资料 在 《0基础学习PyFlink——时间滚动窗口(Tumbling Time Windows)》一文中,我们使用的是运行时间(Tumbling ProcessingTimeWindows)作为窗口的参考时间: reducedkeyed.window(TumblingProcess…...

Git Rebase 优化项目历史
在软件开发过程中,版本控制是必不可少的一环。Git作为当前最流行的版本控制系统,为开发者提供了强大的工具来管理和维护代码历史。git rebase是其中一个高级特性,它可以用来重新整理提交历史,使之更加清晰和线性。本文将详细介绍g…...

两种MySQL OCP认证应该如何选?
很多同学都找姚远老师说要参加MySQL OCP认证培训,但绝大部分同学并不知道MySQL OCP认证有两种,以MySQL 8.0为例。 一种是管理方向,叫:Oracle Certified Professional, MySQL 8.0 Database Administrator(我考试的比较…...

Java用log4j写日志
日志可以方便追踪和调试问题,以前用log4net写日志,换Java了改用log4j写日志,用法和log4net差不多。 到apache包下载下载log4j的包,解压后把下图两个jar包引入工程 先到网站根下加一个log4j2.xml的配置文件来配置日志的格式和参…...

PCTA认证考试-01_TiDB数据库架构概述
TiDB 数据库架构概述 一、学习目标 理解 TiDB 数据库整体结构。了解 TiDB Server,TiKV,TiFlash 和 PD 的主要功能。 二、TiDB 体系架构 1. TiDB Server 2. TiKV OLTP 3. Placement Driver 4. TiFlash OLAP OLTPOLAPHTAP...

路由过滤路由引入
目录 一、实验拓扑 二、实验需求 三、实验步骤 1、配置IP地址 2、配置RIP和OSPF 3、配置路由引入 4、使用路由过滤,使 R4 无法学到 R1 的业务网段路由,要求使用 prefix-list 进行匹配 5、OSPF 区域中不能出现 RIP 协议报文 一、实验拓扑 二、实…...