C++ 重载运算符 addition (+), subtraction (-) and multiplication (*)

news2024/9/23 3:25:43

C++ 重载运算符 addition +, subtraction - and multiplication *

  • 1. Operator Overloading (运算符重载)
  • 2. Developing an Operator Overloading Example
    • 2.1. Adding an Addition Operator (添加加法运算符)
    • 2.2. Overloading Restrictions (重载限制)
    • 2.3. 重载运算符 `-` 和 `*`
  • References

Two special member functions, the constructor and the destructor, that manage creating and discarding objects made to a class specification.
两个特殊的成员函数 (构造函数和析构函数),其作用是管理类对象的创建和删除。

As Bjarne Stroustrup, the creator of C++, suggested at a C++ conference for professional programmers:“Ease yourself into the language. Don’t feel you have to use all of the features, and don’t try to use them all on the first day.”
不要觉得必须使用所有的特性,不要在第一次学习时就试图使用所有的特性。

1. Operator Overloading (运算符重载)

Operator overloading is an example of C++ polymorphism. C++ enables you to define several functions that have the same name, provided that they have different signatures (argument lists).That is called function overloading, or functional polymorphism. Its purpose is to let you use the same function name for the same basic operation, even though you apply the operation to different data types. Operator overloading extends the overloading concept to operators, letting you assign multiple meanings to C++ operators.
运算符重载是一种形式的 C++ 多态。用户能够定义多个名称相同但特征标 (参数列表) 不同的函数的,这被称为函数重载或函数多态,旨在让您能够用同名的函数来完成相同的基本操作,即使这种操作被用于不同的数据类型。运算符重载将重载的概念扩展到运算符上,允许赋予 C++ 运算符多种含义。

C++ lets you extend operator overloading to user-defined types.
C++ 允许将运算符重载扩展到用户定义的类型,例如,允许使用 + 将两个对象相加。

To overload an operator, you use a special function form called an operator function.
要重载运算符,需使用被称为运算符函数的特殊函数形式。

An operator function has the following form, where OP is the symbol for the operator being overloaded:

operatorOP(argument-list)

For example, operator+() overloads the + operator and operator*() overloads the * operator. The OP has to be a valid C++ operator; you can’t just make up a new symbol. For example, you can’t have an operator@() function because C++ has no @ operator. But the operator[]() function would overload the [] operator because [] is the array-indexing operator. Suppose, for example, that you have a SalesPerson class for which you define an operator+() member function to overload the + operator so that it adds sales figures of one SalesPerson object to another. Then, if district2, yong, and qiang are all objects of the SalesPerson class, you can write this equation:
例如,operator+() 重载 + 运算符,operator*() 重载 * 运算符。OP 必须是有效的 C++ 运算符,不能虚构一个新的符号。例如,不能有 operator@() 这样的函数,因为 C++ 中没有 @ 运算符。然而,operator[]() 函数将重载 [] 运算符,因为 [] 是数组索引运算符。例如,假设有一个 SalesPerson 类,并为它定义了一个 operator+() 成员函数,以重载 + 运算符,以便能够将两个 SalesPerson 对象的销售额相加,则如果 district2, yong, and qiang 都是 SalesPerson 类对象,便可以编写这样的等式:

district2 = yong + qiang;

The compiler, recognizing the operands as belonging to the Salesperson class, replaces the operator with the corresponding operator function:

district2 = yong.operator+(qiang);

The function then uses the yong object implicitly (because it invoked the method) and the qiang object explicitly (because it’s passed as an argument) to calculate the sum, which it then returns. Of course, the nice part is that you can use the nifty + operator notation instead of the clunky function notation.
然后该函数将隐式地使用 yong (因为它调用了方法),而显式地使用 qiang 对象 (因为它被作为参数传递),来计算总和,并返回这个值。当然最重要的是,可以使用简便的 + 运算符表示法,而不必使用笨拙的函数表示法。

2. Developing an Operator Overloading Example

Now let’s generalize that to a Time class, using a method to handle addition. Let’s begin with an ordinary method, called Sum(), and then see how to convert it to an overloaded operator.
首先使用一个名为 Sum() 的常规方法,然后介绍如何将其转换为重载运算符。

  • time.h
// Time class before operator overloading
#ifndef TIME_H_
#define TIME_H_

class Time {
private:
	int hours;
	int minutes;

public:
	Time();
	Time(const int h, const int m = 0);
	~Time();

	void AddMinutes(const int m);
	void AddHours(const int h);
	void Reset(const int h = 0, const int m = 0);
	const Time Sum(const Time & time) const;
	void Show() const;
};

#endif

  • time.cpp
#include <iostream>

#include "time.h"

Time::Time() {
	std::cout << "Time::Time()" << std::endl;
	hours = minutes = 0;
}

Time::Time(const int h, const int m) {
	std::cout << "Time::Time(const int h, const int m): h=" << h << ", m=" << m << std::endl;
	hours = h;
	minutes = m;
}

Time::~Time() {
	std::cout << "Time::~Time(): hours=" << hours << ", minutes=" << minutes << std::endl;
}

void Time::AddMinutes(const int m) {
	minutes += m;
	hours += minutes / 60;
	minutes %= 60;
}

void Time::AddHours(const int h) {
	hours += h;
}

void Time::Reset(const int h, const int m) {
	hours = h;
	minutes = m;
}

const Time Time::Sum(const Time & time) const {
	std::cout << "Time::Sum(const Time & time)" << std::endl;
	Time sum;
	sum.minutes = minutes + time.minutes;
	sum.hours = hours + time.hours + sum.minutes / 60;
	sum.minutes %= 60;
	return sum;
}

void Time::Show() const {
	std::cout << hours << " hours, " << minutes << " minutes";
}

  • sample.cpp
#include <iostream>

#include "time.h"

int main() {
	{
		Time planning;
		Time coding(2, 40);
		Time fixing(5, 55);
		Time total;

		std::cout << "planning time = ";
		planning.Show();
		std::cout << std::endl;

		std::cout << "coding time = ";
		coding.Show();
		std::cout << std::endl;

		std::cout << "fixing time = ";
		fixing.Show();
		std::cout << std::endl;

		total = coding.Sum(fixing);
		std::cout << "coding.Sum(fixing) = ";
		total.Show();
		std::cout << std::endl;
	}
	return 0;
}

在这里插入图片描述

Time::Time()
Time::Time(const int h, const int m): h=2, m=40
Time::Time(const int h, const int m): h=5, m=55
Time::Time()
planning time = 0 hours, 0 minutes
coding time = 2 hours, 40 minutes
fixing time = 5 hours, 55 minutes
Time::Sum(const Time & time)
Time::Time()
Time::~Time(): hours=8, minutes=35
Time::~Time(): hours=8, minutes=35
coding.Sum(fixing) = 8 hours, 35 minutes
Time::~Time(): hours=8, minutes=35
Time::~Time(): hours=5, minutes=55
Time::~Time(): hours=2, minutes=40
Time::~Time(): hours=0, minutes=0
请按任意键继续. . .

Note that the argument is a reference but that the return type is not a reference. The reason for making the argument a reference is efficiency. The code would produce the same results if the Time object were passed by value, but it’s usually faster and more memory-efficient to just pass a reference.
Sum() 函数的代码,参数是引用,但返回类型却不是引用。将参数声明为引用的目的是为了提高效率。如果按值传递 Time 对象,代码的功能相同,但传递引用,速度将更快,使用的内存将更少。

However, the return value can not be a reference. The reason is that the function creates a new Time object (sum) that represents the sum of the other two Time objects. Returning the object, as this code does, creates a copy of the object that the calling function can use. If the return type were Time &, however, the reference would be to the sum object. But the sum object is a local variable and is destroyed when the function terminates, so the reference would be a reference to a non-existent object. Using a Time return type, however, means the program constructs a copy of sum before destroying it, and the calling function gets the copy.
然而,返回值不能是引用。因为函数将创建一个新的 Time 对象 (sum),来表示另外两个 Time 对象的和。返回对象将创建对象的副本,而调用函数可以使用它。然而,如果返回类型为 Time &,则引用的将是 sum 对象。但由于 sum 对象是局部变量,在函数结束时将被删除,因此引用将指向一个不存在的对象。使用返回类型 Time 意味着程序将在删除 sum 之前构造它的拷贝,调用函数将得到该拷贝。

Don’t return a reference to a local variable or another temporary object. When the function terminates and the local variable or temporary object disappears, the reference becomes a reference to non-existent data.
不要返回指向局部变量或临时对象的引用。函数执行完毕后,局部变量和临时对象将消失,引用将指向不存在的数据。

2.1. Adding an Addition Operator (添加加法运算符)

You just change the name of Sum() to the odder-looking name operator+(). That’s right: You just append the operator symbol (+, in this case) to the end of operator and use the result as a method name. This is one place where you can use a character other than a letter, a digit, or an underscore in an identifier name.
Time 类转换为重载的加法运算符很容易,只要将 Sum() 的名称改为 operator+() 即可。只要把运算符放到 operator 的后面,并将结果用作方法名即可。在这里,可以在标识符中使用字母、数字或下划线之外的其他字符。

  • time.h
// Time class before operator overloading
#ifndef TIME_H_
#define TIME_H_

class Time {
private:
	int hours;
	int minutes;

public:
	Time();
	Time(const int h, const int m = 0);
	~Time();

	void AddMinutes(const int m);
	void AddHours(const int h);
	void Reset(const int h = 0, const int m = 0);
	Time operator+(const Time & time) const;
	void Show() const;
};

#endif

  • time.cpp
#include <iostream>

#include "time.h"

Time::Time() {
	std::cout << "Time::Time()" << std::endl;
	hours = minutes = 0;
}

Time::Time(const int h, const int m) {
	std::cout << "Time::Time(const int h, const int m): h=" << h << ", m=" << m << std::endl;
	hours = h;
	minutes = m;
}

Time::~Time() {
	std::cout << "Time::~Time(): hours=" << hours << ", minutes=" << minutes << std::endl;
}

void Time::AddMinutes(const int m) {
	minutes += m;
	hours += minutes / 60;
	minutes %= 60;
}

void Time::AddHours(const int h) {
	hours += h;
}

void Time::Reset(const int h, const int m) {
	hours = h;
	minutes = m;
}

Time Time::operator+(const Time & time) const {
	std::cout << "Time::operator+(const Time & time)" << std::endl;
	Time sum;
	sum.minutes = minutes + time.minutes;
	sum.hours = hours + time.hours + sum.minutes / 60;
	sum.minutes %= 60;
	return sum;
}

void Time::Show() const {
	std::cout << hours << " hours, " << minutes << " minutes";
}

  • sample.cpp
#include <iostream>

#include "time.h"

int main() {
	{
		Time planning;
		Time coding(2, 40);
		Time fixing(5, 55);
		Time total;

		std::cout << "planning time = ";
		planning.Show();
		std::cout << std::endl;

		std::cout << "coding time = ";
		coding.Show();
		std::cout << std::endl;

		std::cout << "fixing time = ";
		fixing.Show();
		std::cout << std::endl;

		total = coding + fixing;
		// operator notation
		std::cout << "coding + fixing = ";
		total.Show();
		std::cout << std::endl;

		Time more_fixing(3, 28);
		std::cout << "more fixing time = ";
		more_fixing.Show();
		std::cout << std::endl;
		total = more_fixing.operator+(total);
		// function notation
		std::cout << "more_fixing.operator+(total) = ";
		total.Show();
		std::cout << std::endl;
	}

	return 0;
}

在这里插入图片描述

Time::Time()
Time::Time(const int h, const int m): h=2, m=40
Time::Time(const int h, const int m): h=5, m=55
Time::Time()
planning time = 0 hours, 0 minutes
coding time = 2 hours, 40 minutes
fixing time = 5 hours, 55 minutes
Time::operator+(const Time & time)
Time::Time()
Time::~Time(): hours=8, minutes=35
Time::~Time(): hours=8, minutes=35
coding + fixing = 8 hours, 35 minutes
Time::Time(const int h, const int m): h=3, m=28
more fixing time = 3 hours, 28 minutes
Time::operator+(const Time & time)
Time::Time()
Time::~Time(): hours=12, minutes=3
Time::~Time(): hours=12, minutes=3
more_fixing.operator+(total) = 12 hours, 3 minutes
Time::~Time(): hours=3, minutes=28
Time::~Time(): hours=12, minutes=3
Time::~Time(): hours=5, minutes=55
Time::~Time(): hours=2, minutes=40
Time::~Time(): hours=0, minutes=0
请按任意键继续. . .

Like Sum(), operator+() is invoked by a Time object, takes a second Time object as an argument, and returns a Time object. Thus, you can invoke the operator+() method by using the same syntax that Sum() uses.
Sum() 一样,operator+() 也是由 Time 对象调用的,它将第二个 Time 对象作为参数,并返回一个 Time 对象。因此,可以像调用 Sum() 那样来调用 operator+() 方法。

total = coding.operator+(fixing);  // function notation

但将该方法命令为 operator+() 后,也可以使用运算符表示法 (operator notation):

total = coding + fixing;  // operator notation

Either notation invokes the operator+() method. Note that with the operator notation, the object to the left of the operator is the invoking object, and the object to the right is the one passed as an argument.
这两种表示法都将调用 operator+() 方法。注意,在运算符表示法中,运算符左侧的对象是调用对象,运算符右边的对象是作为参数被传递的对象。

In short, the name of the operator+() function allows it to be invoked by using either function notation or operator notation. The compiler uses the operand types to figure out what to do.
operator+() 函数的名称使得可以使用函数表示法或运算符表示法来调用它,编译器将根据操作数的类型来确定如何做。

int a, b, c;
Time A, B, C;
c = a + b;  // use int addition
C = A + B;  // use addition as defined for Time objects
t4 = t1 + t2 + t3;  // valid?

Because addition is a left-to-right operator, the statement is first translated to this.
由于 + 是从左向右结合的运算符,因此上述语句首先被转换成下面这样:

t4 = t1.operator+(t2 + t3);

Then the function argument is itself translated to a function call, giving the following.
然后, 函数参数本身被转换成一个函数调用:

t4 = t1.operator+(t2.operator+(t3));

The function call t2.operator+(t3) returns a Time object that represents the sum of t2 and t3. This object then becomes the object of the t1.operator+() function call, and that call returns the sum of t1 and the Time object that represents the sum of t2 and t3. In short, the final return value is the sum of t1, t2, and t3, just as desired.
函数调用 t2.operator+(t3) 返回一个 Time 对象,表示 t2t3 的和。该对象成为函数调用 t1.operator+() 的参数,该调用返回 t1 与表示 t2t3 之和的 Time 对象的和。最后的返回值为 t1t2t3 之和,这正是我们期望的。

2.2. Overloading Restrictions (重载限制)

Overloaded operators don’t necessarily have to be member functions. However, at least one of the operands has to be a user-defined type.
重载的运算符不必是成员函数,但必须至少有一个操作数是用户定义的类型。

  • The overloaded operator must have at least one operand that is a user-defined type. This prevents you from overloading operators for the standard types. Thus, you can’t redefine the minus operator (-) so that it yields the sum of two double values instead of their difference. This restriction preserves program sanity, although it may hinder creative accounting.
    重载后的运算符必须至少有一个操作数是用户定义的类型,这将防止用户为标准类型重载运算符。因此,不能将减法运算符 - 重载为计算两个 double 值的和,而不是它们的差。虽然这种限制将对创造性有所影响,但可以确保程序正常运行。

  • You can’t use an operator in a manner that violates the syntax rules for the original operator. For example, you can’t overload the modulus operator (%) so that it can be used with a single operand.
    使用运算符时不能违反运算符原来的句法规则。例如,不能将求模运算符 % 重载成使用一个操作数。

  • Similarly, you can’t alter operator precedence. So if you overload the addition operator to let you add two classes, the new operator has the same precedence as ordinary addition.
    同样,不能修改运算符的优先级。因此,如果将加号运算符重载成将两个类相加,则新的运算符与原来的加号具有相同的优先级。

  • You can’t create new operator symbols. For example, you can’t define an operator**() function to denote exponentiation.
    不能创建新运算符。例如,不能定义 operator**() 函数来表示求幂。

  • 不能重载下面的运算符:

OperatorDescription
sizeofThe sizeof operator
.The membership operator
.*The pointer-to-member operator
::The scope-resolution operator
?:The conditional operator
typeidAn RTTI operator
const_castA type cast operator
dynamic_castA type cast operator
reinterpret_castA type cast operator
static_castA type cast operator

Most of the operators can be overloaded by using either member or nonmember functions. However, you can use only member functions to overload the following operators.
大多数运算符都可以通过成员或非成员函数进行重载,但下面的运算符只能通过成员函数进行重载。

OperatorDescription
=Assignment operator
()Function call operator
[]Subscripting operator
->Class member access by pointer operator
  • 可重载的运算符

在这里插入图片描述

2.3. 重载运算符 -*

  • time.h
// Time class before operator overloading
#ifndef TIME_H_
#define TIME_H_

class Time {
private:
	int hours;
	int minutes;

public:
	Time();
	Time(const int h, const int m = 0);
	~Time();

	void AddMinutes(const int m);
	void AddHours(const int h);
	void Reset(const int h = 0, const int m = 0);
	Time operator+(const Time & time) const;
	Time operator-(const Time & time) const;
	Time operator*(const double factor) const;
	void Show() const;
};

#endif

  • time.cpp
#include <iostream>

#include "time.h"

Time::Time() {
	std::cout << "Time::Time()" << std::endl;
	hours = minutes = 0;
}

Time::Time(const int h, const int m) {
	std::cout << "Time::Time(const int h, const int m): h=" << h << ", m=" << m << std::endl;
	hours = h;
	minutes = m;
}

Time::~Time() {
	std::cout << "Time::~Time(): hours=" << hours << ", minutes=" << minutes << std::endl;
}

void Time::AddMinutes(const int m) {
	minutes += m;
	hours += minutes / 60;
	minutes %= 60;
}

void Time::AddHours(const int h) {
	hours += h;
}

void Time::Reset(const int h, const int m) {
	hours = h;
	minutes = m;
}

Time Time::operator+(const Time & time) const {
	std::cout << "Time::operator+(const Time & time)" << std::endl;
	Time sum;
	sum.minutes = minutes + time.minutes;
	sum.hours = hours + time.hours + sum.minutes / 60;
	sum.minutes %= 60;
	return sum;
}

Time Time::operator-(const Time & time) const {
	std::cout << "Time::operator-(const Time & time)" << std::endl;
	Time diff;
	const int tot1 = time.minutes + 60 * time.hours;
	const int tot2 = minutes + 60 * hours;
	diff.minutes = (tot2 - tot1) % 60;
	diff.hours = (tot2 - tot1) / 60;
	return diff;
}

Time Time::operator*(const double factor) const {
	std::cout << "Time::operator*(const double factor)" << std::endl;
	Time result;
	const long total_minutes = hours * factor * 60 + minutes * factor;
	result.hours = total_minutes / 60;
	result.minutes = total_minutes % 60;
	return result;
}


void Time::Show() const {
	std::cout << hours << " hours, " << minutes << " minutes";
}

  • sample.cpp
#include <iostream>

#include "time.h"

int main() {
	{
		Time weeding(4, 35);
		Time waxing(2, 47);

		Time total;
		Time diff;
		Time yongqiang;

		std::cout << "\nweeding time = ";
		weeding.Show();
		std::cout << std::endl;

		std::cout << "waxing time = ";
		waxing.Show();
		std::cout << std::endl << std::endl;

		total = weeding + waxing;  // use operator+()
		std::cout << "total work time = ";
		total.Show();
		std::cout << std::endl << std::endl;

		diff = weeding - waxing;  // use operator-()
		std::cout << "weeding time - waxing time = ";
		diff.Show();
		std::cout << std::endl << std::endl;

		yongqiang = total * 1.5;  // use operator+()
		std::cout << "adjusted work time = ";
		yongqiang.Show();
		std::cout << std::endl << std::endl;
	}

	return 0;
}

在这里插入图片描述

Time::Time(const int h, const int m): h=4, m=35
Time::Time(const int h, const int m): h=2, m=47
Time::Time()
Time::Time()
Time::Time()

weeding time = 4 hours, 35 minutes
waxing time = 2 hours, 47 minutes

Time::operator+(const Time & time)
Time::Time()
Time::~Time(): hours=7, minutes=22
Time::~Time(): hours=7, minutes=22
total work time = 7 hours, 22 minutes

Time::operator-(const Time & time)
Time::Time()
Time::~Time(): hours=1, minutes=48
Time::~Time(): hours=1, minutes=48
weeding time - waxing time = 1 hours, 48 minutes

Time::operator*(const double factor)
Time::Time()
Time::~Time(): hours=11, minutes=3
Time::~Time(): hours=11, minutes=3
adjusted work time = 11 hours, 3 minutes

Time::~Time(): hours=11, minutes=3
Time::~Time(): hours=1, minutes=48
Time::~Time(): hours=7, minutes=22
Time::~Time(): hours=2, minutes=47
Time::~Time(): hours=4, minutes=35
请按任意键继续. . .

References

[1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/
[2] C++ Primer Plus, 6th Edition, https://www.informit.com/store/c-plus-plus-primer-plus-9780321776402

  • Operator Overloading
  • Time on Our Hands: Developing an Operator Overloading Example

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

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

相关文章

数字统计

import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别// 注意 while 处理多个 caseint a in.nextInt();i…

拯救中国足球,要不尝试一下DDD事件风暴?

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 张逸老师写了新文章《领域建模的常见问题及解决方案》&#xff0c;我来谈一谈对这篇文章的感想。 &#xff08;1&#xff09;文章一开始&#xff0c;张逸老师大大地赞扬了事件风暴&am…

Linux系统中磁盘管理LVM与挂载

Linux系统中磁盘管理LVM与挂载 本文以属于Linux系统基本概念&#xff0c;如果以查找教程教程&#xff0c;解决问题为主&#xff0c;只需要查看本文后半部分。如需要系统性学习请查看本文前半部分。 本文操作极容易导致主机无法自动重启&#xff0c;请慎重操作。操作前务必要进…

JlmPack在军民两用工业软件生态平台的使用

随着信息技术的飞速发展&#xff0c;军民两用工业软件生态平台在国防建设和民用产业中的应用日益广泛。JlmPack作为一款拥有完全自主加权概率模型下的编码算法发明专利的纯国产压缩工具库&#xff0c;其高效、安全、可控的特性在军民两用工业软件生态平台中拥有巨大的应用潜力。…

闲话银行家舍入法,以及在程序中如何实现

前言 相信对于四舍五入的舍入法&#xff0c;大家都耳熟能详&#xff0c;但对于银行家舍入法&#xff0c;可能就会比较少接触了&#xff01; 可是在金融界&#xff0c;银行家舍入法可是大名鼎鼎的主角之一&#xff0c;主要应用于金融领域和涉及货币计算的场合。 那么&#xf…

Clion中怎么切换不同的程序运行

如下图&#xff0c;比如这个文件夹下面有那么多的项目&#xff1a; 那么我想切换不同的项目运行怎么办呢&#xff1f;如果想通过下图的Edit Configurations来设置是不行的&#xff1a; 解决办法&#xff1a; 如下图&#xff0c;选中项目的CMakeLists.txt&#xff0c;右键再点击…

16. Revit API: Family、FamilySymbol、FamilyInstance

前言 前面写着一直絮絮叨叨&#xff0c;感觉不好。想找些表情包来&#xff0c;写得好玩点&#xff0c;但找不到合适的&#xff0c;或者说耗时费力又不满意&#xff0c;而自个儿又做不来表情包&#xff0c;就算了。 其次呢&#xff0c;之前会把部分类成员给抄表列出来&#xf…

电脑缺少dll文件是怎么回事?教你5种有效的解决方法

当您的计算机显示DLL文件已经遗失时&#xff0c;您应如何应对呢&#xff1f;实际上&#xff0c;针对此类DLL文件的处置过程相对来说较为简易。今日&#xff0c;我们在此为大家详细介绍此领域的相关知识&#xff0c;让大家轻松解决电脑中因丢失DLL文件而产生的问题。 一、关于DL…

关于消息队列MQ的举例 | 同步调用与异步调用的区别

为什么要有一个消息代理&#xff1f; 举例&#xff1a; 消息发送者和消息接收者直接连接&#xff0c;就好像外卖员直接把外卖送到顾客的手上。 但如果顾客此刻正在处理自己的事情&#xff0c;不方便拿外卖。 那么外卖员就需要把外卖放在外卖柜上&#xff0c;顾客方便的时候直接…

【前端】面试八股文——meta标签

【前端】面试八股文——meta标签 在HTML文档中&#xff0c;meta标签是一个关键但常被忽视的元素。它位于文档的<head>部分&#xff0c;用于提供关于HTML文档的元数据&#xff08;metadata&#xff09;。这些元数据不会直接显示在页面上&#xff0c;但对搜索引擎优化&…

DDL也会有undo吗?模拟Oracle中DML、DDL与undo的关系,10046跟踪DDL语句

已经有两个月没有更新博客了&#xff0c;主要实在忙毕设和毕业的一些事情&#xff01;这两个月也是非常的精彩呀&#xff0c;充分体会到了职场的和校园的不同&#xff0c;作为一名刚毕业就满 1 年工作经验的牛马人&#xff0c;在两个月期间经历了两次调岗、两次降薪&#xff0c…

Python编程:如何有效等待套接字的读取与关闭

背景介绍 网络编程是现代应用程序开发的重要组成部分&#xff0c;尤其是在大数据和实时通信的背景下。套接字&#xff08;Socket&#xff09;作为网络通信的核心技术&#xff0c;是开发网络应用程序的基础。在Python编程中&#xff0c;如何有效地等待套接字的读取与关闭事件是…

无人机之穿越机注意事项篇

一、检查设备 每次飞行前都要仔细检查穿越机的每个部件&#xff0c;确保所有功能正常&#xff0c;特别是电池和电机。 二、遵守法律 了解并遵循你所在地区关于无人机的飞行规定&#xff0c;避免非法飞行。 三、评估环境 在飞行前检查周围环境&#xff0c;确保没有障碍物和…

补码一位乘法原理(布斯编码详讲)

最近在看补码乘法的时候&#xff0c;感觉到很奇怪的一点&#xff0c;那就是补码的一位乘法&#xff0c;就是上网查了大量的资料都没有理解到它真正的原理&#xff0c;总感觉还是不会。那么&#xff0c;补码乘法的原理到底是什么呢&#xff1f;而让我们一直困惑的点是哪里呢&…

Linux运维:MySQL中间件代理服务器,mycat读写分离应用实验

Mycat适用的场景很丰富&#xff0c;以下是几个典型的应用场景&#xff1a; 1.单纯的读写分离&#xff0c;此时配置最为简单&#xff0c;支持读写分离&#xff0c;主从切换 2.分表分库&#xff0c;对于超过1000万的表进行分片&#xff0c;最大支持1000亿的单表分片 3.多租户应…

【多线程】生产者消费者模型(代码实现)

文章目录 生产者消费者模型介绍生产者消费者模型的特点基于BlockingQueue的生产者消费者模型 生产者消费者模型介绍 生产者消费模型是一种常见的多线程编程模式&#xff0c;广泛应用于解决并发编程中的数据共享和任务调度问题。在该模型中&#xff0c;我们将生产数据并放入缓冲…

“都市绿洲,健康生活新纪元“ —全方位打造高科技多功能智慧健康园

咸宁&#xff0c;这座被誉为"桂花之乡"和"华中康养区"的城市&#xff0c;如同一朵绽放在湖北东南的璀璨明珠。这里桂花飘香&#xff0c;温泉涌动&#xff0c;将自然的馈赠与人文的智慧完美融合。漫步在咸宁&#xff0c;你会被满城金黄的桂花树所吸引&#…

SCSA第四天

ASPF FTP --- 文件传输协议 Tftp --- 简单文件传输协议 FTP协议相较于Tftp协议 ---- 1&#xff0c;需要进行认证 2&#xff0c;拥有一套完整的命令集 用户认证 防火墙管理员认证 ---- 校验登录者身份合法性 用户认证 --- 上网行为管理中的一环 上网用户认证 --- 三层认证…

QImage显示图片像素

在Qt中&#xff0c;QImage 类是用来表示和处理图像的。如果你想查看或显示一个图片的像素数据&#xff0c;你可以使用 QImage 提供的方法来访问这些数据。以下是一些基本的方法来获取和显示图片的像素信息&#xff1a; 获取图像的像素格式&#xff1a; 使用 QImage::format() …

redis相关知识记录

redis基本数据类型 Redis⽀持五种主要数据结构&#xff1a;字符串&#xff08;Strings&#xff09;、列表&#xff08;Lists&#xff09;、哈希表&#xff08;Hashes&#xff09;、集合&#xff08;Sets&#xff09;和有序集合&#xff08;Sorted Sets&#xff09;。这些数据结…