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

news2025/5/9 18:00:02

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 - d2
        int 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 < d2
 bool 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 <= d2
 bool 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 += -50
 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) const
 {
        Date tmp = *this;
        tmp += day;
        return tmp;
 }
 
// d1 -= 100
 Date& 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;
 }
 //++d1
 Date& 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 - d2
 int 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) 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 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; //OK
		cout << 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;
}

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

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

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

相关文章

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

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

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

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

DeepSeek实战--手搓实现Agent

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

线性代数——行列式⭐

目录 一、行列式的定义⭐ 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地址过滤或添加到白名…

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

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

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

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

【随笔】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/…

Unity-Socket通信实例详解

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

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

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

【计算机网络】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…

Apache Doris 使用指南:从入门到生产实践

目录 一、Doris 核心概念 1.1 架构组成 1.2 数据模型 二、Doris 部署方式 2.1 单机部署&#xff08;测试环境&#xff09; 2.2 集群部署&#xff08;生产环境&#xff09; 三、数据操作指南 3.1 数据库与表管理 3.2 数据导入方式 3.2.1 批量导入 3.2.2 实时导入 3.…

26届秋招收割offer指南

26届暑期实习已经陆续启动&#xff0c;这也意味着对于26届的同学们来说&#xff0c;“找工作”已经提上了日程。为了帮助大家更好地准备暑期实习和秋招&#xff0c;本期主要从时间线、学习路线、核心知识点及投递几方面给大家介绍&#xff0c;希望能为大家提供一些实用的建议和…

拷贝多个Excel单元格区域为图片并粘贴到Word

Excel工作表Sheet1中有两个报表&#xff0c;相应单元格区域分别定义名称为Report1和Report2&#xff0c;如下图所示。 现在需要将图片拷贝图片粘贴到新建的Word文档中。 示例代码如下。 Sub Demo()Dim oWordApp As ObjectDim ws As Worksheet: Set ws ThisWorkbook.Sheets(&…

【Bluedroid】蓝牙 SDP(服务发现协议)模块代码解析与流程梳理

本文深入剖析Bluedroid蓝牙协议栈中 SDP&#xff08;服务发现协议&#xff09;服务记录的全生命周期管理流程&#xff0c;涵盖初始化、记录创建、服务搜索、记录删除等核心环节。通过解析代码逻辑与数据结构&#xff0c;揭示各模块间的协作机制&#xff0c;包括线程安全设计、回…

中国自动驾驶研发解决方案,第一!

4月28日&#xff0c;IDC《中国汽车云市场(2024下半年)跟踪》报告发布&#xff0c;2024下半年中国汽车云市场整体规模达到65.1亿元人民币&#xff0c;同比增长27.4%。IDC认为&#xff0c;自动驾驶技术深化与生成式AI的发展将为汽车云打开新的成长天花板&#xff0c;推动云计算在…

Kubernetes(k8s)学习笔记(四)--入门基本操作

本文通过kubernetes部署tomcat集群&#xff0c;来学习和掌握kubernetes的一些入门基本操作 前提条件 1.各个节点处于Ready状态&#xff1b; 2.配置好docker镜像库(否则会出现ImagePullBackOff等一些问题)&#xff1b; 3.网络配置正常(否则即使应用发布没问题&#xff0c;浏…