【C++篇】C++类与对象深度解析(三):类的默认成员函数详解

文章目录

  • 【C++篇】C++类与对象深度解析(三)
    • 前言
      • 4. 运算符重载基本概念
        • 4.1 运算符重载的基本概念
        • 4.2 重载运算符的规则
        • 4.3 成员函数重载运算符
        • 4.4 运算符重载的优先级与结合性
        • 4.5 运算符重载中的限制与特殊情况
          • 4.5.1 不能创建新的操作符
          • 4.5.2 无法重载的运算符
          • 4.5.3 前置和后置递增运算符的重载
          • 补充: `.*`(成员指针访问运算符)
            • 介绍:
            • 示例:使用 `.*` 运算符访问成员函数
            • 示例:使用 `.*` 运算符访问成员变量
            • 不能重载 `.*` 运算符
      • 5 赋值运算符重载
        • 5.1 赋值运算符重载必须定义为成员函数
        • 5.2 有返回值,建议写成当前类类型的引用
        • 5.3 编译器自动生成的默认赋值运算符
        • 5.4 显式实现赋值运算符重载的必要性
        • 5.5 赋值运算符与析构函数的关系
          • 总结
      • 6. 取地址运算符重载
        • 6.1 const成员函数
        • 6.2 取地址运算符重载
          • 普通取地址运算符重载
          • const取地址运算符重载
          • 总结
  • 写在最后

【C++篇】C++类与对象深度解析(三)

前言

💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力!

👍 点赞、收藏与分享:觉得这篇文章对你有帮助吗?别忘了点赞、收藏并分享给更多的小伙伴哦!你们的支持是我不断进步的动力!
🚀 分享给更多人:如果你觉得这篇文章对你有帮助,欢迎分享给更多对C++感兴趣的朋友,让我们一起进步!

接上篇:
【C++篇】C++类与对象深度解析(二):类的默认成员函数详解

在上一篇文章中,我们讨论了C++类的默认成员函数,包括构造函数、析构函数和拷贝构造函数。本篇我们将继续探索剩余的默认成员函数,这些是C++面向对象编程中不可或缺的高级特性。掌握这些功能将帮助您更加灵活地设计和实现C++类。❤️

4. 运算符重载基本概念

4.1 运算符重载的基本概念

运算符重载允许我们为类对象自定义运算符的行为,这样当我们对类对象使用这些运算符时,它们会按照我们定义的方式执行。如果没有定义对应的运算符重载,编译器将会报错,因为它不知道如何处理这些运算符。

  • 运算符重载的定义:运算符重载是一个特殊的函数,名字是operator加上要重载的运算符。
  • 参数数量:重载函数的参数数量取决于运算符的类型。一元运算符有一个参数,二元运算符有两个参数。

示例:重载==运算符

#include<iostream>
using namespace std;class Number {
public:Number(int value = 0) : _value(value) {}// 重载==运算符用于比较两个Number对象是否相等bool operator==(const Number& n) const{return _value == n._value;}private:int _value;
};int main()
{Number n1(10);Number n2(10);if (n1 == n2) {cout << "两个数相等。" << endl;} else {cout << "两个数不相等。" << endl;}return 0;
}

解释

  • operator==:这个重载允许我们直接使用==来比较两个Number对象是否相等,而不需要手动检查它们的内部值。

4.2 重载运算符的规则
  • 函数的名字:重载的函数名称必须是operator加上运算符,例如operator+operator==
  • 参数和返回类型:重载的运算符函数需要根据需要设置参数和返回类型。对于二元运算符,左侧对象传给第一个参数,右侧对象传给第二个参数。

示例:重载+运算符

#include<iostream>
using namespace std;class Number {
public:Number(int value = 0) : _value(value) {}// 重载+运算符,用于两个Number对象相加Number operator+(const Number& n) const{return Number(_value + n._value);}void Print() const{cout << "Value: " << _value << endl;}private:int _value;
};int main()
{Number n1(10);Number n2(20);Number n3 = n1 + n2; // 使用重载的+运算符n3.Print(); // 输出: Value: 30return 0;
}

解释

  • operator+:这个运算符重载允许我们使用+运算符来相加两个Number对象,并返回一个新的Number对象。

4.3 成员函数重载运算符

如上面的例子,当运算符重载定义为类的成员函数时,第一个运算对象会隐式地传递给this指针,因此成员函数的参数数量比操作数少一个。

示例:重载-运算符

#include<iostream>
using namespace std;class Number {
public:Number(int value = 0) : _value(value) {}// 重载-运算符,用于两个Number对象相减Number operator-(const Number& n) const{return Number(_value - n._value);}void Print() const{cout << "Value: " << _value << endl;}private:int _value;
};int main()
{Number n1(20);Number n2(10);Number n3 = n1 - n2; // 使用重载的-运算符n3.Print(); // 输出: Value: 10return 0;
}

解释

  • operator-:这个重载允许我们使用-运算符来减去两个Number对象的值,并返回一个新的Number对象。

4.4 运算符重载的优先级与结合性

虽然我们可以改变运算符的行为,但其优先级和结合性与内置类型运算符保持一致。这意味着我们不能通过重载运算符来改变它们的运算顺序。

示例:重载*运算符

#include<iostream>
using namespace std;class Number {
public:Number(int value = 0) : _value(value) {}// 重载*运算符,用于两个Number对象相乘Number operator*(const Number& n) const{return Number(_value * n._value);}void Print() const{cout << "Value: " << _value << endl;}private:int _value;
};int main()
{Number n1(5);Number n2(4);Number n3 = n1 * n2; // 使用重载的*运算符n3.Print(); // 输出: Value: 20return 0;
}

解释

  • operator*:这个重载允许我们使用*运算符来相乘两个Number对象的值,并返回一个新的Number对象,其优先级还是高于重载后的+运算符。

4.5 运算符重载中的限制与特殊情况
4.5.1 不能创建新的操作符

在C++中,虽然可以重载大多数运算符,但不能创建新的操作符。也就是说,我们不能使用C++语法中没有的符号来创建新的运算符。例如,operator@是非法的,因为@符号不是C++中的有效运算符。

解释

  • 只能重载C++已有的运算符,如+, -, *, /, ==等。不能创建诸如operator@这样的运算符,因为@不属于C++的运算符集合。

示例:尝试创建一个新的操作符(会报错)

#include<iostream>
using namespace std;class Number {
public:Number(int value = 0) : _value(value) {}// 错误:不能定义新的运算符Number operator@(const Number& n) const{return Number(_value + n._value);}private:int _value;
};int main()
{Number n1(10);Number n2(20);// n1 @ n2; // 错误:@ 不是一个合法的C++运算符return 0;
}

结果

  • 编译器会报错,因为@不是C++中的有效运算符,不能通过operator@进行重载。
4.5.2 无法重载的运算符

在C++中,有五个运算符是不能重载的,这些运算符的行为在语言中是固定的,不能改变。

这些运算符包括:

  1. .(成员访问运算符)
  2. .*(成员指针访问运算符)见以下补充
  3. ::(作用域解析运算符)
  4. sizeof(大小计算运算符)
  5. ?:(三元条件运算符)

解释

  • 这些运算符的行为在C++中是固定的,无法通过重载改变它们的语义或使用方式。

示例:尝试重载不能重载的运算符(会报错)

#include<iostream>
using namespace std;class Number {
public:Number(int value = 0) : _value(value) {}// 错误:不能重载sizeof运算符int operator sizeof() const{return _value;}private:int _value;
};int main()
{Number n1(10);// int size = sizeof(n1); // 错误:无法重载sizeof运算符return 0;
}

结果

  • 编译器会报错,因为sizeof是一个固定的运算符,无法通过重载改变其行为。
4.5.3 前置和后置递增运算符的重载

在C++中,递增运算符++可以有两种形式:前置递增后置递增。它们的功能类似,但实现方式不同。

  • 前置递增:先递增,然后返回递增后的值。
  • 后置递增:先返回当前值,然后递增。

为了区分前置和后置递增运算符,C++规定在重载后置递增运算符时,必须增加一个int参数。这只是一个区分符,并没有实际用途。

示例:重载前置和后置递增运算符

前置直接操作对象,传引用返回,而后置返回副本,用传值返回

#include<iostream>
using namespace std;class Number {
public:Number(int value = 0) : _value(value) {}// 重载前置++Number& operator++(){++_value;return *this;}// 重载后置++Number operator++(int){Number tmp = *this; // 保存当前值++_value;           // 递增return tmp;         // 返回原始值}void Print() const{cout << "Value: " << _value << endl;}private:int _value;
};int main()
{Number n1(5);++n1; // 前置++n1.Print(); // 输出: Value: 6n1++; // 后置++n1.Print(); // 输出: Value: 7return 0;
}

解释

  • operator++():这是前置递增的实现。先递增,然后返回递增后的对象自身。
  • operator++(int):这是后置递增的实现。先保存当前对象的副本,然后递增,并返回副本。

结果

  • 前置递增直接修改并返回对象自身,而后置递增返回递增前的副本,之后再进行递增。

这里我们直接使用的普通++类型来实现+1操作,在之后实现了+=运算符重载后可以实现复用,这在最后类和对象的实践篇:日期类的实现会讲到


补充: .*(成员指针访问运算符)
介绍:

.* 是 C++中的成员指针访问运算符,用于通过对象访问指向该对象成员的指针。这个运算符主要用在需要通过指针访问对象的成员函数或成员变量的场景中。

在 C++ 中,.*->* 运算符提供了类似于.-> 的功能,但用于成员指针操作。因为.* 这种运算符在使用上非常特殊,因此不能进行重载。

示例:使用 .* 运算符访问成员函数

假设我们有一个类 MyClass,其中包含一个成员函数 Func,我们可以通过成员指针访问并调用这个函数。

#include<iostream>
using namespace std;class MyClass {
public:void Func() {cout << "MyClass::Func() 被调用了" << endl;}
};int main() {MyClass obj;             // 创建类对象void (MyClass::*pf)() = &MyClass::Func;  // 定义成员函数指针,并指向MyClass的Func函数// 通过对象和成员函数指针调用函数(obj.*pf)();  // 使用 .* 运算符调用成员函数return 0;
}

解释

  • void (MyClass::*pf)() = &MyClass::Func;:这行代码定义了一个指向 MyClass 成员函数的指针 pf,并将其初始化为指向 Func 函数的地址。
  • (obj.*pf)();:使用 .* 运算符,通过 obj 对象调用 pf 所指向的成员函数 Func
示例:使用 .* 运算符访问成员变量

同样的方式可以用于访问成员变量,通过成员指针操作符,我们可以通过一个对象来访问其成员变量。

#include<iostream>
using namespace std;class MyClass {
public:int value;  // 成员变量
};int main() {MyClass obj;              // 创建类对象obj.value = 42;           // 直接访问成员变量int MyClass::*pValue = &MyClass::value;  // 定义成员变量指针,并指向MyClass的value成员// 通过对象和成员变量指针访问成员变量cout << "Value: " << obj.*pValue << endl;  // 使用 .* 运算符访问成员变量return 0;
}

解释

  • int MyClass::*pValue = &MyClass::value;:这行代码定义了一个指向 MyClass 成员变量的指针 pValue,并将其初始化为指向 value 变量的地址。
  • obj.*pValue:使用 .* 运算符,通过 obj 对象访问 pValue 所指向的成员变量 value
不能重载 .* 运算符

由于 .* 运算符的特殊性,它不能被重载。.* 的行为在 C++ 语言中已经固定,主要用于通过对象访问其成员指针所指向的成员。

示例:尝试重载 .*(会报错)

#include<iostream>
using namespace std;class MyClass {
public:int value;// 错误:不能重载 .* 运算符int operator.*() const {return value;}
};int main() {MyClass obj;obj.value = 42;// 编译错误:无法重载 .* 运算符// cout << obj.* << endl;return 0;
}

结果

  • 尝试重载 .* 运算符会导致编译错误,因为这个运算符在 C++ 中是固定的,不能改变其行为。

5 赋值运算符重载

赋值运算符重载是一个特殊的运算符重载,用于将一个对象的状态复制到另一个已经存在的对象中。需要注意的是,赋值运算符重载与拷贝构造函数是不同的,拷贝构造用于初始化一个新对象,而赋值运算符则用于给已经存在的对象赋值。

5.1 赋值运算符重载必须定义为成员函数

赋值运算符重载是C++的一个特殊运算符重载,必须作为类的成员函数来定义。这是因为赋值运算符总是需要操作当前对象(this指针),因此它不能作为全局函数来实现。

示例:定义赋值运算符重载

#include<iostream>
using namespace std;class MyClass {
public:MyClass(int value = 0) : _value(value) {}// 赋值运算符重载,参数是const类型的引用MyClass& operator=(const MyClass& other) {if (this != &other) {  // 防止自我赋值_value = other._value;}return *this;  // 返回当前对象的引用,以支持链式赋值}void Print() const {cout << "Value: " << _value << endl;}private:int _value;
};int main() {MyClass obj1(10);MyClass obj2(20);obj2 = obj1;  // 调用赋值运算符重载obj2.Print(); // 输出: Value: 10return 0;
}

解释

  • operator=:这是赋值运算符的重载函数。this指针指向当前对象,other是被赋值的对象。
  • if (this != &other):检查当前对象是否与传入对象是同一个对象,如果是同一个对象,则跳过赋值操作,以避免自我赋值引起的问题。
  • return *this;:返回当前对象的引用,这允许连续的赋值操作,例如a = b = c;
5.2 有返回值,建议写成当前类类型的引用

赋值运算符重载函数通常返回当前对象的引用,这样可以安全支持链式赋值操作,即多个对象之间连续赋值的语句。

示例:支持链式赋值

#include<iostream>
using namespace std;class MyClass {
public:MyClass(int value = 0) : _value(value) {}// 赋值运算符重载,返回当前对象的引用MyClass& operator=(const MyClass& other) {if (this != &other) {_value = other._value;}return *this;}void Print() const {cout << "Value: " << _value << endl;}private:int _value;
};int main() {MyClass obj1(10);MyClass obj2(20);MyClass obj3(30);obj1 = obj2 = obj3;  // 链式赋值obj1.Print(); // 输出: Value: 30obj2.Print(); // 输出: Value: 30return 0;
}

解释

  • 在链式赋值中,obj2 = obj3 会首先执行,operator= 返回 obj2 的引用,然后 obj1 = obj2 执行,这样 obj1 最终也得到了 obj3 的值。
5.3 编译器自动生成的默认赋值运算符

如果我们没有显式定义赋值运算符重载,编译器会自动生成一个默认的赋值运算符

这个默认的赋值运算符执行的是浅拷贝操作:对于内置类型成员变量,逐个字节地复制值;对于自定义类型成员变量,则调用它们的赋值运算符重载。

示例:使用编译器生成的默认赋值运算符

#include<iostream>
using namespace std;class MyClass {
public:MyClass(int value = 0) : _value(value) {}// 未显式定义赋值运算符重载,编译器会自动生成void Print() const {cout << "Value: " << _value << endl;}private:int _value;
};int main() {MyClass obj1(10);MyClass obj2(20);obj2 = obj1;  // 使用编译器生成的默认赋值运算符obj2.Print(); // 输出: Value: 10return 0;
}

解释

  • 在这个例子中,编译器生成了一个默认的赋值运算符,它对内置类型的成员变量执行浅拷贝操作。
5.4 显式实现赋值运算符重载的必要性

在一些情况下,例如类中包含指针成员或其他动态资源,浅拷贝可能会导致问题。这时,我们需要显式实现赋值运算符重载来进行深拷贝,以确保对象的独立性。

示例:显式实现赋值运算符进行深拷贝

#include<iostream>
using namespace std;class MyClass {
public:MyClass(int value = 0) : _value(new int(value)) {}// 拷贝构造函数MyClass(const MyClass& other) {_value = new int(*other._value);}// 赋值运算符重载MyClass& operator=(const MyClass& other) {if (this != &other) {delete _value; // 删除旧的动态内存_value = new int(*other._value); // 分配新的动态内存并复制值}return *this;}~MyClass() {delete _value; // 析构函数中释放动态内存}void Print() const {cout << "Value: " << *_value << endl;}private:int* _value; // 指针类型成员变量
};int main() {MyClass obj1(10);MyClass obj2(20);obj2 = obj1;  // 使用自定义的赋值运算符进行深拷贝obj1.Print(); // 输出: Value: 10obj2.Print(); // 输出: Value: 10return 0;
}

解释

  • 在这个例子中,MyClass 类中包含一个指针成员变量 _value,我们需要自定义赋值运算符以确保进行深拷贝,即在赋值时为 _value 分配新的内存,并将值复制到新分配的内存中。
5.5 赋值运算符与析构函数的关系

如果一个类显式定义了析构函数来释放动态资源,那么它通常也需要显式定义赋值运算符重载,以避免浅拷贝带来的资源管理问题。

示例:显式实现析构函数和赋值运算符重载

#include<iostream>
using namespace std;class MyClass {
public:MyClass(int value = 0) : _value(new int(value)) {}// 拷贝构造函数MyClass(const MyClass& other) {_value = new int(*other._value);}// 赋值运算符重载MyClass& operator=(const MyClass& other) {if (this != &other) {delete _value;_value = new int(*other._value);}return *this;}// 析构函数~MyClass() {delete _value;}void Print() const {cout << "Value: " << *_value << endl;}private:int* _value;
};int main() {MyClass obj1(10);MyClass obj2(20);obj2 = obj1;  // 使用自定义的赋值运算符进行深拷贝obj1.Print(); // 输出: Value: 10obj2.Print(); // 输出: Value: 10return 0;
}

解释

  • MyClass 包含一个指针成员变量 _value,我们通过显式实现赋值运算符和析构函数来管理动态内存,确保不会因为浅拷贝导致资源泄漏或多次释放同一块内存。
总结

赋值运算符重载在管理动态资源、确保对象独立性以及支持链式赋值时非常有用。通过理解赋值运算符的特性和如何正确实现它,我们可以编写更健壮的C++程序,避免浅拷贝带来的问题。


6. 取地址运算符重载

在C++中,取地址运算符&用于获取对象的内存地址。在大多数情况下,编译器自动生成的取地址运算符重载已经足够使用。然而,在某些特殊场景下,我们可能希望控制或限制对象地址的获取方式,这时候我们就可以手动重载取地址运算符。

6.1 const成员函数

const成员函数是指用const修饰的成员函数。它主要用于确保成员函数不会修改类的成员变量,从而保证函数的只读特性。

  • 用法:将const修饰符放在成员函数的参数列表之后。
  • 效果const实际修饰的是成员函数中隐含的this指针,表示在该成员函数中不能对类的任何成员进行修改。

示例代码:const成员函数

#include<iostream>
using namespace std;class Date {
public:Date(int year = 1, int month = 1, int day = 1) : _year(year), _month(month), _day(day) {}// const成员函数,表示不会修改类成员变量void Print() const {cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main() {// 非const对象可以调用const成员函数Date d1(2024, 7, 5);d1.Print();// const对象也可以调用const成员函数const Date d2(2024, 8, 5);d2.Print();return 0;
}

解释

  • void Print() constconst修饰了Print函数,表示它不会修改Date类的成员变量。this指针的类型在这个函数中变为const Date* const,意味着它指向的对象及指针本身都不能被修改。
  • 权限的缩小const对象只能调用const成员函数,而非const对象可以调用任意成员函数,这体现了一种权限的缩小。
6.2 取地址运算符重载

取地址运算符&通常用于获取对象的地址。通过重载该运算符,可以自定义获取对象地址的方式,甚至可以禁止获取地址或返回一个伪造的地址。

普通取地址运算符重载

普通取地址运算符用于非const对象,重载后可以控制返回对象的地址。

示例代码:普通取地址运算符重载

#include<iostream>
using namespace std;class Date {
public:Date(int year = 1, int month = 1, int day = 1) : _year(year), _month(month), _day(day) {}// 重载普通取地址运算符Date* operator&() {// return this;  // 返回对象的真实地址return nullptr;  // 返回空指针,伪装地址}private:int _year;int _month;int _day;
};int main() {Date d1(2024, 7, 5);Date* p1 = &d1;  // 使用重载的取地址运算符if (p1 == nullptr) {cout << "未获取到真实地址" << endl;} else {cout << "对象的地址为: " << p1 << endl;}return 0;
}

解释

  • Date* operator&():这是普通的取地址运算符重载。可以根据需求决定是否返回对象的真实地址,也可以返回nullptr或其他伪造地址,以达到某些特定需求(如禁止获取对象地址)的目的。
const取地址运算符重载

const取地址运算符用于const对象,重载后可以控制如何返回const对象的地址。

示例代码:const取地址运算符重载

#include<iostream>
using namespace std;class Date {
public:Date(int year = 1, int month = 1, int day = 1) : _year(year), _month(month), _day(day) {}// 重载const取地址运算符const Date* operator&() const {// return this;  // 返回对象的真实地址return nullptr;  // 返回空指针,伪装地址}private:int _year;int _month;int _day;
};int main() {const Date d1(2024, 8, 5);const Date* p1 = &d1;  // 使用重载的取地址运算符if (p1 == nullptr) {cout << "未获取到真实地址" << endl;} else {cout << "对象的地址为: " << p1 << endl;}return 0;
}

解释

  • const Date* operator&() const:这是const取地址运算符重载。它同样可以控制是否返回const对象的真实地址或者伪装地址。
总结
  • 默认行为:在大多数情况下,编译器自动生成的取地址运算符已经足够使用,不需要手动重载。
  • 特殊需求:在一些特殊场景(如禁止获取对象地址)下,可以通过重载取地址运算符来自定义行为。
  • const修饰:通过const修饰符可以控制成员函数的只读特性,确保在函数中不修改类成员变量。同时,const取地址运算符重载可以用于const对象,确保其地址获取方式受到控制。

写在最后

运算符重载使C++类对象能像基本数据类型一样操作,赋予类更直观的行为。通过重载 +- 等运算符,我们可以实现对象间的运算和比较。赋值运算符尤其重要,确保对象在涉及动态资源时安全地复制。const 成员函数则提供了数据保护,避免意外修改。总的来说,运算符重载让代码更加简洁优雅,增强了程序的灵活性。


以上就是关于【C++篇】C++类与对象深度解析(三):类的默认成员函数详解的内容,到此为止我们就把类的六个默认成员函数讲解完啦,各位大佬有什么问题欢迎在评论区指正,或者私信我也是可以的啦,您的支持是我创作的最大动力!❤️

在这里插入图片描述

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

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

相关文章

QT 带箭头的控件QPolygon

由于对当前项目需要绘制一个箭头控件&#xff0c;所以使用了QPainter和QPolygon来进行绘制&#xff0c;原理就是计算填充&#xff0c;下面贴出代码和效果图 这里简单介绍下QPolygon QPolygon是继承自 QVector<QPoint>那么可以很简单的理解为&#xff0c;他就是一个点的…

Leetcode面试经典150题-138.随机链表的复制

题目比较简单&#xff0c;重点是理解思想&#xff0c;random不管&#xff0c;copy一定要放在next 而且里面的遍历过程不能省略 解法都在代码里&#xff0c;不懂就留言或者私信 /* // Definition for a Node. class Node {int val;Node next;Node random;public Node(int val…

springboot-创建连接池

操作数据库 代码开发步骤&#xff1a; pom.xml文件配置依赖properties文件配置连接数据库信息&#xff08;连接池用的是HikariDataSource&#xff09;数据库连接池开发 configurationproperties和value注解从properties文件中取值bean方法开发 service层代码操作数据库 步骤&am…

数据分析师的得力助手:vividime Desktop让数据分析变得更简单高效

在数据驱动决策的今天&#xff0c;数据分析已成为企业不可或缺的一部分。面对海量的数据和复杂的业务需求&#xff0c;一款高效、易用的报表工具显得尤为重要。本文将深入解析为何一款优秀的报表工具对于数据分析至关重要&#xff0c;并以市场上备受好评的免费BI工具——vividi…

集成学习详细介绍

以下内容整理于&#xff1a; 斯图尔特.罗素, 人工智能.现代方法 第四版(张博雅等译)机器学习_温州大学_中国大学MOOC(慕课)XGBoost原理介绍------个人理解版_xgboost原理介绍 个人理解-CSDN博客 集成学习(ensemble)&#xff1a;选择一个由一系列假设h1, h2, …, hn构成的集合…

YOLOv10改进系列,YOLOv10损失函数更换为Powerful-IoU(2024年最新IOU),助力高效涨点

改进前训练结果: 改进后的结果: 摘要 边界框回归(BBR)是目标检测中的核心任务之一,BBR损失函数显著影响其性能。然而,观察到现有基于IoU的损失函数存在不合理的惩罚因子,导致回归过程中锚框扩展,并显著减缓收敛速度。为了解决这个问题,深入分析了锚框扩展的原因。针…

【网络】详解HTTP协议的CGI机制和CGI进程

目录 引言 CGI机制模型 伪代码示例 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 CGI机制是HTTP协议提供的偏底层的一套机制&#xff0c;也是非常重要的机制——它让大量的业务进程和HTPP协议解耦。而CGI进程是业务层的&#xff0c;用来处理各种数据&#xff0c;比…

OpenCV结构分析与形状描述符(24)检测两个旋转矩形之间是否相交的一个函数rotatedRectangleIntersection()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 测两个旋转矩形之间是否存在交集。 如果存在交集&#xff0c;则还返回交集区域的顶点。 下面是一些交集配置的例子。斜线图案表示交集区域&#…

孙怡带你深度学习(2)--PyTorch框架认识

文章目录 PyTorch框架认识1. Tensor张量定义与特性创建方式 2. 下载数据集下载测试展现下载内容 3. 创建DataLoader&#xff08;数据加载器&#xff09;4. 选择处理器5. 神经网络模型构建模型 6. 训练数据训练集数据测试集数据 7. 提高模型学习率 总结 PyTorch框架认识 PyTorc…

Vue2电商平台项目 (三) Search模块、面包屑(页面自己跳自己)、排序、分页器!

文章目录 一、Search模块1、Search模块的api2、Vuex保存数据3、组件获取vuex数据并渲染(1)、分析请求数据的数据结构(2)、getters简化数据、渲染页面 4、Search模块根据不同的参数获取数据(1)、 派发actions的操作封装为函数(2)、设置带给服务器的参数(3)、Object.assign整理参…

如何通过OceanBase的多级弹性扩缩容能力应对业务洪峰

每周四晚上的10点&#xff0c;都有近百万的年轻用户进入泡泡玛特的抽盒机小程序&#xff0c;共同参与到抢抽盲盒新品的活动中。瞬间的并发流量激增对抽盒机小程序的系统构成了巨大的挑战&#xff0c;同时也对其数据库的扩容能力也提出了更高的要求。 但泡泡玛特的工程师们一点…

Redhat 7,8,9系(复刻系列) 一键部署Oracle19c rpm

Oracle19c前言 Oracle 19c 是甲骨文公司推出的一款企业级关系数据库管理系统,它带来了许多新的功能和改进,使得数据库管理更加高效、安全和可靠。以下是关于 Oracle 19c 的详细介绍: 主要新特性 多租户架构:支持多租户架构,允许多个独立的数据库实例在同一个物理服务器上…

JDBC API详解一

DriverManager 驱动管理类&#xff0c;作用&#xff1a;1&#xff0c;注册驱动&#xff1b;2&#xff0c;获取数据库连接 1&#xff0c;注册驱动 Class.forName("com.mysql.cj.jdbc.Driver"); 查看Driver类源码 static{try{DriverManager.registerDriver(newDrive…

java十进制码、六进制码和字符码的转换

一、字符转换为ASCII码&#xff1a; int i(int)1; 二、ASCII码转换为字符&#xff1a; char ch (char)40; 三、十六进制码转换为字符&#xff1a; char charValue (char)\u0040; package week3;public class check_point4_8 {public static void main(String[] args) {S…

谷歌怎么像图里这样多开贴吧号??

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

数据库三范式和ER图详解

数据库设计三范式 第一范式&#xff1a;要求数据表中的字段&#xff08;列&#xff09;不可再分(原子性) 第二范式&#xff1a;不存在非关键字段(非主键)对关键字段(主键)的部分依赖 ps: 主要是针对联合主键,非主键不能只依赖联合主键的一部分 联合主键,即多个列组成的主键 第…

Python | Leetcode Python题解之第414题第三大的数

题目&#xff1a; 题解&#xff1a; class Solution:def thirdMax(self, nums: List[int]) -> int:a, b, c None, None, Nonefor num in nums:if a is None or num > a:a, b, c num, a, belif a > num and (b is None or num > b):b, c num, belif b is not No…

代码随想录Day 46|动态规划完结,leetcode题目:647. 回文子串、516.最长回文子序列

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 题目题目一&#xff1a;647. 回文子串解题思路&#xff1a;暴力解法动态规划 题目二&#xff1a; 516.最长回文子序列解题思路&#xff1a; 动态规划总结动规五部曲基础概念常见问题类型 动态规划…

Web3入门指南:从基础概念到实际应用

Web3&#xff0c;即“去中心化的第三代互联网”&#xff0c;正在逐步改变我们对互联网的传统认知。从最初的静态网页&#xff08;Web1.0&#xff09;到互动平台和社交媒体为主的互联网&#xff08;Web2.0&#xff09;&#xff0c;Web3的目标是让用户重新掌握对数据和数字资产的…

LeetCode[中等] 合并区间

以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 思路 区间排序&#xff1a; 开始位置 ——> 升序排…