当前位置: 首页 > article >正文

C++类与对象—下:夯实面向对象编程的阶梯

9. 赋值运算符重载

9.1 运算符重载

在 C++ 里,运算符重载能够让自定义类型的对象像内置类型那样使用运算符,这极大地提升了代码的可读性与可维护性。运算符重载本质上是一种特殊的函数,其函数名是 operator 加上要重载的运算符。

下面是运算符重载的一般语法:

返回类型 operator 运算符 (参数列表) {// 函数体
}

运算符重载有一些规则和限制:

  • 不能创建新的运算符,只能重载已有的运算符。

  • 不改变运算符的优先级和结合性。

  • 至少有一个操作数是自定义类型。重载操作符至少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如:int operator+(int x, int y)

  • .* :: sizeof ?: . 注意以上5个运算符不能重载。

  • 一个类需要重载哪些运算符,是看哪些运算符重载后有意义,比如Date类重载operator-就有意义,但是重载operator+就没有意义。

  • 重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。

  • 重载<<和>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调用时就变成了对象<<cout,不符合使用习惯和可读性。重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第二个形参位置当类类型对象。

#include<iostream>using namespace std;// 编译报错:“operator +”必须⾄少有⼀个类类型的形参
int operator+(int x, int y){return x - y;}class A{public:void func(){cout << "A::func()" << endl;}
};typedef void(A::*PF)(); //成员函数指针类型int main(){// C++规定成员函数要加&才能取到函数指针PF pf = &A::func;A obj;//定义ob类对象temp // 对象调⽤成员函数指针时,使⽤.*运算符(obj.*pf)();return 0;}

9.2 赋值运算符重载

赋值运算符重载是运算符重载的一种特殊情况,它允许我们自定义对象之间的赋值行为。赋值运算符的函数名是 operator=

下面是赋值运算符重载的一般语法:

类名& operator=(const 类名& other) {if (this != &other) {// 执行赋值操作}return *this;
}

这里需要注意几个要点:

  • 返回值类型通常是当前类类型引用类名&,引用返回可以提高效率,这样也可以支持连续赋值,例如 a = b = c
  • 参数通常是 const 类名&,这避免了不必要的拷贝(传值传参会有拷贝),同时保证不会修改传入的对象。
  • 有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值目的是为了支持连续赋值场景。
  • 没有显式实现时,编译器会自动生成一个默认赋值运算符重载,默认赋值运算符重载行为跟默认构造函数类似,对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。
class Date
{public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){cout << " Date(const Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day;}// 传引⽤返回减少拷⻉// d1 = d2;Date& operator=(const Date& d){// 不要检查⾃⼰给⾃⼰赋值的情况if (this != &d){_year = d._year;_month = d._month;_day = d._day;}// d1 = d2表达式的返回对象应该为d1,也就是*this return *this;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;};int main(){Date d1(2024, 7, 5);Date d2(d1);Date d3(2024, 7, 6);d1 = d3;// 需要注意这⾥是拷⻉构造,不是赋值重载// 请牢牢记住赋值重载完成两个已经存在的对象直接的拷⻉赋值// ⽽拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象Date d4 = d1;return 0;}

9.3 日期类的实现

下面我们来实现一个日期类 Date,并对运算符进行重载:

#pragma once#include<iostream>using namespace std;#include<assert.h>class Date{// 友元函数声明 我们下面马上就会说friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);public:Date(int year = 1900, int month = 1, int day = 1);void Print() const;// 直接定义类里⾯,他默认是
inline // 频繁调⽤int GetMonthDay(int year, int month){assert(month > 0 && month < 13);static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };// 365天 5h + if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){ return 29;}else{return monthDayArray[month];}}bool CheckDate();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;// d1 += 天数Date& operator+=(int day);Date operator+(int day) const;// d1 -= 天数Date& operator-=(int day);Date operator-(int day) const;// d1 - d2int operator-(const Date& d) const;// ++d1 -> d1.operator++()Date& operator++();// d1++ -> d1.operator++(0)// 为了区分,构成重载,给后置++,强⾏增加了⼀个int形参// 这⾥不需要写形参名,因为接收值是多少不重要,也不需要⽤// 这个参数仅仅是为了跟前置++构成重载区分Date operator++(int);Date& operator--();Date operator--(int);// 流插⼊// 不建议,因为Date* this占据了⼀个参数位置,使⽤d<<cout不符合习惯//void operator<<(ostream& out);private:int _year;int _month;int _day;};// 重载ostream& operator<<(ostream& out, const Date& d);istream& operator>>(istream& in, Date& d);// Date.cpp#include"Date.h"bool Date::CheckDate(){if (_month < 1 || _month > 12|| _day < 1 || _day > GetMonthDay(_year, _month)){return false;}else{return true;}}Date::Date(int year, int month, int day){_year = year;_month = month;_day = day;if (!CheckDate()){cout << "⽇期⾮法" << endl;}}void Date::Print() const{cout << _year << "-" << _month << "-" << _day << endl;}// d1 < d2bool 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){return _day < d._day;}}return false;}// d1 <= d2bool 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 _year == d._year&& _month == d._month&& _day == d._day;}bool Date::operator!=(const Date& d) const{return !(*this == d);}// d1 += 50// d1 += -50Date& 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) const{Date tmp = *this;tmp += day;return tmp;}// d1 -= 100Date& Date::operator-=(int day) 
{if (day < 0){return *this += -day;}_day -= day;while (_day <= 0){--_month;if (_month == 0){_month = 12;_year--;}// 借上⼀个⽉的天数_day += GetMonthDay(_year, _month);}return *this;}Date Date::operator-(int day) const{Date tmp = *this;tmp -= day;return tmp;}//++d1Date& Date::operator++(){*this += 1;return *this;}// d1++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;}// d1 - d2int Date::operator-(const Date& d) const{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n * flag;}ostream& operator<<(ostream& out, const Date& d){out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;}istream& operator>>(istream& in, Date& d){cout << "请依次输⼊年月日:>";in >> d._year >> d._month >> d._day;if (!d.CheckDate()){cout << "日期⾮法" << endl;}return in;}

大家可以自写测试函数进行自行测试,再此我不过多赘述

10. 取地址运算符重载

10.1 const 成员函数

在 C++ 中,const 成员函数是指那些不会修改对象状态的成员函数。在函数声明和定义时,在参数列表后面加上 const 关键字,就可以将该函数声明为 const 成员函数。

下面是 const 成员函数的一般语法:

返回类型 函数名(参数列表) const {// 函数体
}

const 成员函数有以下几个特点:

  • 只能调用其他的 const 成员函数。
  • const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。const 修饰Date类的Print成员函数,Print隐含的this指针由Date* const this变为const Date* const this

以下是一个示例:

 #include<iostream>using namespace std;class Date{
public:public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// void Print(const Date* const this) constvoid 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 Date d2(2024, 8, 5);d2.Print();return 0;}

在上述代码中,getData 函数被声明为 const 成员函数,因此可以被 const 对象调用。

10.2 取地址运算符重载

取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,⼀般这两个函数编译器自动生成的就可以够我们用了,不需要去显示实现。除非⼀些很特殊的场景,比如我们不想让别人取到当前类对象的地址,就可以自己实现⼀份,胡乱返回一个地址。

 class Date{ 
public :Date* operator&(){return this;// return nullptr;}const Date* operator&()const{return this;// return nullptr;}private :int _year ; // 年int _month ; // ⽉int _day ; // ⽇};

11. 友元

11.1 友元的概念

在 C++ 中,封装性是面向对象编程的重要特性之一,它通过访问限定符(publicprivateprotected)来控制类的成员的访问权限。然而,在某些特殊情况下,我们可能需要让一个外部的函数或类能够访问某个类的私有成员。这时,就可以使用友元机制。友元机制提供了一种突破封装性的方式,允许特定的外部函数或类访问另一个类的私有和保护成员。

11.2 友元函数

友元函数是一种在类外部定义的普通函数,但通过在类内部使用 friend 关键字进行声明,使得该函数可以访问类的私有和保护成员。

示例代码

#include <iostream>
class Point {
private:int x;int y;
public:Point(int x = 0, int y = 0) : x(x), y(y) {}// 声明友元函数friend void printPoint(const Point& p);
};// 友元函数的定义
void printPoint(const Point& p) {std::cout << "x: " << p.x << ", y: " << p.y << std::endl;
}int main() {Point p(3, 4);printPoint(p);return 0;
}

在上述代码中,printPoint 函数是 Point 类的友元函数,因此它可以直接访问 Point 类的私有成员 xy

11.3 友元类

友元类是指一个类可以访问另一个类的私有和保护成员。在一个类中使用 friend 关键字声明另一个类为友元类,那么这个友元类的所有成员函数都可以访问该类的私有和保护成员。

示例代码

#include <iostream>
class A {
private:int data;
public:A(int d = 0) : data(d) {}// 声明 B 为 A 的友元类friend class B;
};class B {
public:void accessA(A& a) {std::cout << "Accessing A's data: " << a.data << std::endl;}
};int main() {A a(10);B b;b.accessA(a);return 0;
}

在这个例子中,BA 的友元类,所以 B 类的成员函数 accessA 可以访问 A 类的私有成员 data

11.4 友元的注意事项

  • 友元关系是单向的,即如果 AB 的友元,并不意味着 BA 的友元。
  • 友元关系不具有传递性,即如果 AB 的友元,BC 的友元,并不意味着 AC 的友元。
  • 友元破坏了类的封装性,增加耦合度,使用时需要谨慎(不宜多用)。

12. 类型转换&&static成员

12.1 类型转换

C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数、
构造函数前面加explicit就不再支持隐式类型转换
比如:

#include<iostream>
using namespace std;
class A
{ 
public:// 构造函数explicit就不再⽀持隐式类型转换// explicit A(int a1)A(int a1):_a1(a1){}//explicit A(int a1, int a2)A(int a1, int a2):_a1(a1),_a2(a2){}void Print(){cout << _a1 << " " << _a2 << endl;}
private:int _a1 = 1;int _a2 = 2;
};
int main()
{// 1构造⼀个A的临时对象,再⽤这个临时对象拷⻉构造aa3// 编译器遇到连续构造+拷⻉构造->优化为直接构造A aa1 = 1;aa1.Print();const A& aa2 = 1;// C++11之后才⽀持多参数转化A aa3 = { 2,2 };return 0;
}

12.2 static成员

直接给出注意的点

  • 用static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进行初始化
  • 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。
    static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。
  • 静态成员函数中可以访问其他的静态成员,但是不能访问非静态的,因为没有this指针。
  • 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。
  • 突破类域就可以访问静态成员,可以通过类名::静态成员对象.静态成员来访问静态成员变量和静态成员函数。
  • 静态成员也是类的成员,受public、protected、private访问限定符的限制。
  • 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表
// 实现⼀个类,计算程序中创建出了多少个类对象?
#include<iostream>
using namespace std;
class A
{ 
public:A(){++_scount;} A(const A& t){++_scount;} ~A(){--_scount;} static int GetACount(){return _scount;}
private:// 类⾥⾯声明static int _scount;
};
// 类外⾯初始化
int A::_scount = 0;int main()
{cout << A::GetACount() << endl;A a1, a2;A a3(a1);cout << A::GetACount() << endl;cout << a1.GetACount() << endl;// 编译报错:error C2248: “A::_scount”: ⽆法访问 private 成员(在“A”类中声明)//cout << A::_scount << endl;return 0;
}

13. 内部类

如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。

  • 内部类默认是外部类的友元类。
  • 内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。
#include<iostream>
using namespace std;
class A
{ 
private:static int _k;int _h = 1;
public:class B // B默认就是A的友元{ public:void foo(const A& a){cout << _k << endl; //OKcout << a._h << endl; //OK}};
};
int A::_k = 1;int main()
{cout << sizeof(A) << endl;A::B b;A aa;b.foo(aa);return 0;
}

这个题相信大家都不陌生,然而如果不让你使用循环你该怎么做呢???
求1+2+3+…+n_牛客

class Solution {private:static int ret;static int i;class Sum{public:Sum(){ret+=i;++i;}};
public:int Sum_Solution(int n) {Sum a[n];return ret;}
};
int Solution::ret=0;
int Solution::i=1;

是不是使用内部类的时候初始化直接求出来了哦,你就说这个方法巧不巧妙

14. 匿名对象

匿名对象是指没有名字的对象,它通常在创建后立即使用,使用完后就会被销毁。匿名对象可以用于临时传递参数或者调用函数。
匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。
比如:

#include <iostream>
class Test {
public:Test() {std::cout << "Constructor called" << std::endl;}~Test() {std::cout << "Destructor called" << std::endl;}void print() {std::cout << "Print function called" << std::endl;}
};int main() {// 创建匿名对象并调用 print 函数Test().print();//使用完后立即销毁return 0;
}

15. 对象拷贝时的编译器优化 *

  • 现代编译器会为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少一些传参和传参过程中可以省略的拷贝。
  • 如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。当前主流的相对新一点的编译器对于连续⼀个表达式步骤中的连续拷贝会进行合并优化,有些更新更"激进"的编译还会进行跨行跨表达式的合并优化。

在此以VS为例简要说明

#include<iostream>
using namespace std;
class A
{ 
public:A(int a = 0):_a1(a){cout << "A(int a)" << endl;} A(const A& aa):_a1(aa._a1){cout << "A(const A& aa)" << endl;} A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a1 = aa._a1;} return *this;
} ~A(){cout << "~A()" << endl;}
private:int _a1 = 1;
};
void f1(A aa)
{}
A f2()
{A aa;return aa;
} 
int main()
{// 传值传参A aa1;f1(aa1);cout << endl;// 隐式类型,连续构造+拷⻉构造->优化为直接构造f1(1);// ⼀个表达式中,连续构造+拷⻉构造->优化为⼀个构造f1(A(2));cout << endl;cout << "***********************************************" << endl;// 传值返回// 返回时⼀个表达式中,连续拷⻉构造+拷⻉构造->优化⼀个拷⻉构造 (vs2019)// ⼀些编译器会优化得更厉害,进⾏跨⾏合并优化,直接变为构造。(vs2022)f2();cout << endl;// 返回时⼀个表达式中,连续拷⻉构造+拷⻉构造->优化⼀个拷⻉构造 (vs2019)// ⼀些编译器会优化得更厉害,进⾏跨⾏合并优化,直接变为构造。(vs2022)A aa2 = f2();cout << endl;// ⼀个表达式中,连续拷⻉构造+赋值重载->⽆法优化aa1 = f2();cout << endl;return 0;
}

如果你看到了这,那么恭喜你,关于类与对象的大部分内容基本上说清楚了,至于其他的,咱们在后面慢慢说,期待与你的下次相遇~~~
在这里插入图片描述

相关文章:

C++类与对象—下:夯实面向对象编程的阶梯

9. 赋值运算符重载 9.1 运算符重载 在 C 里&#xff0c;运算符重载能够让自定义类型的对象像内置类型那样使用运算符&#xff0c;这极大地提升了代码的可读性与可维护性。运算符重载本质上是一种特殊的函数&#xff0c;其函数名是 operator 加上要重载的运算符。 下面是运算…...

MCP认证全解析:从零到微软认证专家

MCP认证全解析&#xff1a;从零到微软认证专家 什么是MCP认证&#xff1f; Microsoft Certified Professional&#xff08;MCP&#xff09;是由微软官方颁发的技术认证&#xff0c;旨在验证IT从业者在微软技术栈&#xff08;如Azure、Windows Server、SQL Server等&#xff0…...

裸辞8年前端的面试笔记——JavaScript篇(一)

裸辞后的第二个月开始准备找工作&#xff0c;今天是第三天目前还没有面试&#xff0c;现在的行情是一言难尽&#xff0c;都在疯狂的压价。 下边是今天复习的个人笔记 一、事件循环 JavaScript 的事件循环&#xff08;Event Loop&#xff09;是其实现异步编程的关键机制。 从…...

TCP 与 UDP报文

** TCP 与 UDP报文** 1. 引言 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09; 和 UDP&#xff08;用户数据报协议&#xff09; 是两种最核心的传输层协议。它们各自适用于不同的场景&#xff0c;理解其工作原理对开发高性能网络应用至关重要。本文将详细解…...

开上“Python跑的车”——自动驾驶数据可视化的落地之道

开上“Python跑的车”——自动驾驶数据可视化的落地之道 一、自动驾驶离不开“看得见”的智能 在智能汽车时代,自动驾驶已然不是“炫技”标签,而是一场技术实力的全面拉锯战。而在这场战役中,有一个极其关键但常被忽略的领域,叫做: 数据可视化(Data Visualization)。 为…...

Linux中安装mysql8,转载及注意事项

一、先前往官网下载mysql8 下载地址&#xff1a; https://dev.mysql.com/downloads/选择Linux 二、删除Linux中的mysql&#xff08;如果有的话&#xff09;&#xff0c;上传安装包 1、先查看mysql是否存在&#xff0c;命令如下&#xff1a; rpm -qa|grep -i mysql如果使用这…...

可以下载blender/fbx格式模型网站

glbxz.com glbxz.com可以下载blender/fbx格式模型。当然里面有免费的...

SpringBoot的汽车商城后台管理系统源码开发实现

概述 汽车商城后台管理系统专为汽车4S店和经销商设计&#xff0c;提供全面的汽车管理系统解决方案。 主要内容 1. 核心功能模块 系统提供以下主要功能&#xff1a; ​​销售管理​​&#xff1a;记录销售信息&#xff0c;跟踪交易进度​​客户管理​​&#xff1a;维护客户…...

从入门到深入:Vue.js 学习全攻略

一、Vue.js 入门基础 &#xff08;一&#xff09;Vue.js 简介与环境搭建 Vue.js 是一套用于构建用户界面的渐进式 JavaScript 框架&#xff0c;所谓渐进式&#xff0c;意味着开发者可以根据项目需求&#xff0c;灵活地选择使用 Vue 的功能。它既可以嵌入到简单的 HTML 页面中…...

C++八股--6--mysql 日志与并发控制

这里向大家介绍一下数据库基础&#xff1a;共分为以下章节 10前序.日志系统 这是数据库的核心。我放到首页来介绍&#xff0c;给大家一个前置概念&#xff0c;方便进行更好的学习 日志文件我们用来记录事务对数据库更新操作的文件&#xff0c;分为以记录为单位的文件和数据块…...

DeepSeek实战--手搓实现Agent

1.背景 要学习AI agent&#xff0c;只会用agent 框架&#xff0c;还不够&#xff0c;一旦框架出现问题&#xff0c;没法快速的排查出问题。 学习就应该“知其然&#xff0c;更应该知其所以然” &#xff0c;今天我们就用编码的方式实现一个简单的agent 。我们模拟一套AI学生评…...

Hutool的`BeanUtil.toBean`方法详解

BeanUtil.toBean是Hutool工具包中一个非常实用的JavaBean转换工具方法&#xff0c;它能够方便地将一个对象&#xff08;通常是Map或另一个JavaBean&#xff09;转换为目标类型的JavaBean实例。 方法签名 public static <T> T toBean(Object source, Class<T> tar…...

线性代数——行列式⭐

目录 一、行列式的定义⭐ 1-1、三阶行列式练习 1-2、下面介绍下三角行列式、上三角行列式、对角行列式 ​编辑 二、行列式的性质 2-1、性质1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6 ​编辑 2-2、性质7 2- 3、拉普拉斯定理、克莱姆法则 三…...

iPhone手机连接WiFi异常解决方法

iPhone手机连接WiFi异常解决方法 一、问题现象二、iPhone连不上可能的原因三、基础排查与快速修复第一步:重启大法第二步:忽略网络,重新认证第三步:关闭“私有无线局域网地址”第四步:修改DNS服务器第五步:还原网络设置四、路由器端排查及设置关闭MAC地址过滤或添加到白名…...

Spark缓存

生活中缓存容量受成本和体积限制&#xff08;比如 CPU 缓存只有几 MB 到几十 MB&#xff09;&#xff0c;但会通过算法&#xff08;如 “最近最少使用” 原则&#xff09;智能决定存什么&#xff0c;确保存的是 “最可能被用到的数据”。 1. 为什么需要缓存&#xff1f; 惰性执…...

计算机视觉与深度学习 | 基于Transformer的低照度图像增强技术

基于Transformer的低照度图像增强技术通过结合Transformer的全局建模能力和传统图像增强理论(如Retinex),在保留颜色信息、抑制噪声和平衡亮度方面展现出显著优势。以下是其核心原理、关键公式及典型代码实现: 一、原理分析 1. 全局依赖建模与局部特征融合 Transformer的核…...

学习设计模式《八》——原型模式

一、基础概念 原型模式的本质是【克隆生成对象】&#xff1b; 原型模式的定义&#xff1a;用原型实例指定创建对象的种类&#xff0c;并通过拷贝这些原型创建新的对象 。 原型模式的功能&#xff1a; 1、通过克隆来创建新的对象实例&#xff1b; 2、为克隆出来的新对象实例复制…...

疗愈服务预约小程序源码介绍

基于ThinkPHP、FastAdmin和UniApp开发的疗愈服务预约小程序源码&#xff0c;这款小程序在功能设计和用户体验上都表现出色&#xff0c;为疗愈行业提供了一种全新的服务模式。 该小程序源码采用了ThinkPHP作为后端框架&#xff0c;保证了系统的稳定性和高效性。同时&#xff0c…...

如何通过外网访问内网?对比5个简单的局域网让互联网连接方案

在实际应用中&#xff0c;常常需要从外网访问内网资源&#xff0c;如远程办公访问公司内部服务器、在家访问家庭网络中的设备等。又或者在本地内网搭建的项目应用需要提供互联网服务。以下介绍几种常见的外网访问内网、内网提供公网连接实现方法参考。 一、公网IP路由器端口映…...

Linux 服务器静态 IP 配置初始化指南

✅ 第一步&#xff1a;确认网络管理方式 运行以下命令判断系统使用的网络管理服务&#xff1a; # 检查 NetworkManager 是否活跃 systemctl is-active NetworkManager# 检查 network&#xff08;旧服务&#xff09;是否活跃 systemctl is-active network或者检查配置路径&…...

【随笔】Google学术:but your computer or network may be sending automated queries.

文章目录 一、问题复述二、问题原因三、解决 前提&#xff1a;你的xxx是自己做的&#xff0c;你自己可以管理&#xff0c;而不是用的那些劣质✈场。 一、问题复述 &#x1f7e2;如下图所示&#xff1a;可以打开谷歌学术&#xff0c;但是一搜索就是这个界面。 二、问题原因 …...

长事务:数据库中的“隐形炸弹“——金仓数据库运维避坑指南

引言&#xff1a;凌晨三点的告警 "张工&#xff01;生产库又告警了&#xff01;"凌晨三点的电话铃声总是格外刺耳。运维团队发现数据库频繁进入单用户模式&#xff0c;排查发现某核心表的年龄值&#xff08;Age&#xff09;已突破20亿大关。经过一夜奋战&#xff0c…...

ubuntu nobel + qt5.15.2 设置qss语法识别正确

问题展示 解决步骤 首选项里面的高亮怎么编辑选择都没用。如果已经有generic-highlighter和css.xml&#xff0c;直接修改css.xml文件最直接&#xff01; 在generic-highlighter目录下找到css.xml文件&#xff0c;位置是&#xff1a;/opt/Qt/Tools/QtCreator/share/qtcreator/…...

优化01-统计信息

Oracle 的统计信息是数据库优化器生成高效执行计划的核心依据。它记录了数据库对象&#xff08;如表、索引、列等&#xff09;的元数据信息&#xff0c;帮助优化器评估查询成本并选择最优执行路径。以下是关于 Oracle 统计信息的详细介绍&#xff1a; 一、统计信息的分类 表统…...

Unity-Socket通信实例详解

今天我们来讲解socket通信。 首先我们需要知道什么是socket通信&#xff1a; Socket本质上就是一个个进程之间网络通信的基础&#xff0c;每一个Socket由IP端口组成&#xff0c;熟悉计网的同学应该知道IP主要是应用于IP协议而端口主要应用于TCP协议&#xff0c;这也证明了Sock…...

MATLAB仿真定点数转浮点数(对比VIVADO定点转浮点)

MATLAB仿真定点数转浮点数 定点数可设置位宽&#xff0c;小数位宽&#xff1b;浮点数是单精度浮点数 对比VIVADO定点转浮点 目录 前言 一、定点数 二、浮点数 三、定点数转浮点数 四、函数代码 总结 前言 在FPGA上实现算法时&#xff0c;相比MATLAB实现往往需要更长的开发…...

配置Jupyter Notebook环境及Token认证(Linux服务器)

配置Jupyter Notebook环境及Token认证&#xff08;Linux服务器&#xff09; 背景 在Ubuntu 18.04.6 LTS服务器&#xff08;IP: 39.105.167.2&#xff09;上&#xff0c;基于虚拟环境pytorch_env&#xff0c;通过Mac终端&#xff08;SSH&#xff09;配置Jupyter Notebook环境&…...

【计算机网络】Cookie、Session、Token之间有什么区别?

大家在日常使用浏览器时可能会遇到&#xff1a;是否清理Cookie&#xff1f;这个问题。 那么什么是Cookie呢&#xff1f;与此相关的还有Session、Token这些。这两个又是什么呢&#xff1f; 本文将对这三个进行讲解区分&#xff0c;如果对小伙伴有帮助的话&#xff0c;也请点赞、…...

SpringCloud服务拆分:Nacos服务注册中心 + LoadBalancer服务负载均衡使用

SpringCloud中Nacos服务注册中心 LoadBalancer服务负载均衡使用 前言Nacos工作流程nacos安装docker安装window安装 运行nacos微服务集成nacos高级特性1.服务集群配置方法效果图模拟服务实例宕机 2.权重配置3.环境隔离 如何启动集群节点本地启动多个节点方法 LoadBalancer集成L…...

Spring AI 集成 DeepSeek V3 模型开发指南

Spring AI 集成 DeepSeek V3 模型开发指南 前言 在人工智能飞速发展的当下&#xff0c;大语言模型不断推陈出新&#xff0c;DeepSeek AI 推出的开源 DeepSeek V3 模型凭借其卓越的推理和问题解决能力备受瞩目。与此同时&#xff0c;Spring AI 作为一个强大的框架&#xff0c;…...