C++知识整理day3类与对象(下)——赋值运算符重载、取地址重载、列表初始化、友元、匿名对象、static

文章目录

  • 1.赋值运算符重载
    • 1.1 运算符重载
    • 1.2 赋值运算符重载
  • 2.取地址重载
    • 2.1 const成员函数
    • 2.2 取地址运算符重载
  • 3.类与对象的补充
    • 3.1 再探构造函数---初始化列表
    • 3.2 类型转换
    • 3.3 static成员
    • 3.4 友元
    • 3.5 内部类
    • 3.6 匿名对象
    • 3.7 对象拷贝时的编译器优化

1.赋值运算符重载

赋值运算符重载是六个默认成员函数之一,在讲解这个我们要先了解一下运算符重载。

1.1 运算符重载

当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使用运算符的时候,必须转换成调用对应运算符重载,若没有对应的运算符重载,则会报编译错误。

注意:对于下面的例子中,都是使用的Date类。

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << '-' << _month << '-' << _day << endl;}private:int _year;int _month;int _day;
};
  1. 运算符重载是具有特别名字的函数,他的名字是由operator和后面要定义的运算符共同构成。和其他函数一样,他也具有其返回类型和参数列表以及函数体。
  2. 重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第⼆个参数。(注意:成员函数的第一个参数默认是this指针。

示例:
如果我们写了这行代码,那么毫无疑问编译器会报错,因为对于类类型判断相等的符号编译器是无法识别的(只有内置类型才可以使用):
在这里插入图片描述
那么我们就需要写一个赋值运算符重载了,如下:
在这里插入图片描述
Q1:上面的代码为什么会报错?
A1:我们是定义了一个全局函数,而类内的成员变量是私有的,即类外是无法访问的。

Q2:我们如何解决上面错误呢?
A2:我们有四个方法:

  • 成员变为公有(不建议,不安全)
  • Date提供GetYear之类的函数
  • 使用友元函数(之后会介绍)
  • 重载为成员函数(推荐,下面第3点就会讲到)
  1. 如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数⽐运算对象少⼀个。

示例:
在这里插入图片描述

  1. 运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。
  2. 不能通过连接语法中没有的符号来创建新的操作符:⽐如operator@。
  3. ⼀个类需要重载哪些运算符,是看哪些运算符重载后有意义,⽐如Date类重载operator-就有意义(两个日期相减得到天数),但是重载operator+就没有意义(两个日期相加没有意义)。
  4. 重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。
  5. 重载<<和>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了 对象<<cout,不符合使⽤习惯和可读性。重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象。

示例:

//流插入
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;return in;
}

Q:为什么返回值要是ostream&和istream&?
A:因为我们他的对象是为了让他支持连续输入输出 的特性,对于&是因为流插入和流提取是不允许被修改的。

对于上面的讲解,下面我会依次给出例子:

示例①:重载运算符+和+=

// 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;
}// d1 + 50
Date Date::operator+(int day)
{Date tmp(*this);tmp._day += day;while (tmp._day > GetMonthDay(tmp._year, tmp._month)){tmp._day -= GetMonthDay(tmp._year, tmp._month);tmp._month++;if (tmp._month == 13){tmp._year++;tmp._month = 1;}}return tmp;
}

由于每月的天数不一样,并且闰年的二月会少一天,所以定义GetMonthDay是获取某年某月的天数,如下:

int GetMonthDay(int year, int month)
{static int day[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && (year % 4 == 0 && year % 100 != 0) && year % 400 == 0)return 29;return day[month];
}

但是对于上面的重载运算符+和+=,其实我么你只需要实现一个就可以了,另外一个只需要通过已经重载的那个运算符来使用它即可,如下是两种不同重载对比:
在这里插入图片描述
我们可以发现,我们先重载运算符+=,在用+=就可以间接使用运算符重载+,这样的效率更高,只需要调用两次拷贝构造。

示例②:同上,重载运算符-和-=

// d1 -= 50
Date& Date::operator-=(int day)
{if (day < 0){return *this += (-day);}_day -= day;while(_day <= 0){//借位--_month;if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}// d1 - 50
Date Date::operator-(int day)
{Date tmp = *this;tmp -= day;return tmp;
}

示例③:重载运算符>(大于)

// >
bool Date::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)return _day > d._day;return false;
}

示例④:运算符重载==(等于)

// == 
bool Date::operator==(const Date& d)
{return _year == d._year&& _month == d._month&& _day == d._day;
}

有了>和==运算符重载,可以衍生如下运算符重载:

  1. 大于等于
// >=
bool Date::operator>=(const Date& d)
{return *this > d || *this == d;
}
  1. 小于
// <
bool Date::operator<(const Date& d)
{return !(*this >= d);
}
  1. 小于等于
// <=
bool Date::operator<=(const Date& d)
{return !(*this >= d);
}
  1. !=
// !=
bool Date::operator!=(const Date& d)
{return !(*this == d);
}

示例⑤:前置++和后置++

// 前置++
Date& Date::operator++()
{*this += 1;return *this;
}// 后置++
Date Date::operator++(int)
{Date tmp = *this;*this += 1;return tmp;
}

注意:对于前置++,我们返回的是Date&,因为前置++,自增之后,我们返回的是+1的值。而后置++,我们返回的是没有+1之前的值,但是我们本身this指向的对象时自增了的。

1.2 赋值运算符重载

赋值运算符重载是⼀个默认成员函数,⽤于完成两个已经存在的对象直接的拷⻉赋值,这⾥要注意跟拷⻉构造区分,拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象。

赋值运算符的特点:

  1. 赋值运算符重载是⼀个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成const 当前类类型引⽤,否则会传值传参会有拷⻉。
  2. 有返回值,且建议写成当前类类型引⽤,引⽤返回可以提⾼效率,有返回值⽬的是为了⽀持连续赋值场景。
  3. 没有显式实现时,编译器会⾃动⽣成⼀个默认赋值运算符重载,默认赋值运算符重载⾏为跟默认构造函数类似,对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型成员变量会调⽤他的赋值运算符重载。
  4. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的赋值运算符重载就可以完成需要的拷⻉,所以不需要我们显⽰实现赋值运算符重载。像Stack这样的类,虽然也都是内置类型,但是_a指向了资源,编译器⾃动⽣成的赋值运算符重载完成的值拷⻉/浅拷⻉不符合我们的需求,所以需要我们⾃⼰实现深拷⻉(对指向的资源也进⾏拷⻉)。像MyQueue这样的类型内部主要是⾃定义类型Stack成员,编译器⾃动⽣成的赋值运算符重载会调⽤Stack的赋值运算符重载,也不需要我们显⽰实现MyQueue的赋值运算符重载。这⾥还有⼀个⼩技巧,如果⼀个类显⽰实现了析构并释放资源,那么他就需要显⽰写赋值运算符重载,否则就不需要。(与拷贝构造函数类似)

示例:

class Date
{
public:Date(int year, int month, int day){_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;}void Print(){cout << _year << '-' << _month << '-' << _day << endl;}// 传引⽤返回减少拷⻉// d1 = d2;Date& operator=(const Date& d){// 不要忘记检查⾃⼰给⾃⼰赋值的情况if (this != &d){_year = d._year;_month = d._month;_day = d._day;}// d1 = d2表达式的返回对象应该为d1,也就是*thisreturn *this;}private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 11, 28);Date d2(d1);Date d3(2024, 11, 11);d1 = d3;// 需要注意这⾥是拷⻉构造,不是赋值重载// 请牢牢记住赋值重载完成两个已经存在的对象直接的拷⻉赋值// ⽽拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象Date d4 = d1;return 0;
}

2.取地址重载

2.1 const成员函数

  • 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后面
  • const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。const 修饰Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为 const Date* const this

意思就是我们在成员函数的后面加上了const,就意味着不可以修改this指向的对象了。

注意:

  1. const对象必须调用const成员函数,这是权限的平移
  2. const对象若调用非const成员函数,会报错误,这是权限的放大
  3. 非const对象调用const成员函数,是允许的,这是权限的缩小

2.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 ; // ⽇
};

3.类与对象的补充

3.1 再探构造函数—初始化列表

  • 之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。

示例:

class Time
{
public:Time(int hour):_hour(hour) //初始化列表{cout << "Time()" << endl;}
private:int _hour;
};
  • 每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地⽅。
  • 引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始化,否则会编译报错
    Q:为什么这三种情况必须在初始化列表进行初始化呢?
    A:我们知道,①引用是不可以修改的,他不像指针可以修改,也不像指针初始化成空。在之前我们就提到过:引用必须初始化和不可以修改。②const修饰的成员变量是不可以进行修改的,他是一个常变量,存储到内存中的代码段(只读变量)。③对于自定义的类类型当中还存在自定义的类类型,我们必须调用它的默认构造函数,不然就会报错。

示例:

class Time
{
public:Time(int hour):_hour(hour) //初始化列表{cout << "Time()" << endl;}
private:int _hour;
};class Date
{
public:Date(int& x, int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day), _t(12), _ref(x), _n(1){// error C2512: “Time”: 没有合适的默认构造函数可⽤// error C2530 : “Date::_ref” : 必须初始化引⽤// error C2789 : “Date::_n” : 必须初始化常量限定类型的对象}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;Time _t; // 没有默认构造int& _ref; // 引⽤const int _n; // const
};int main()
{int i = 0;Date d1(i);d1.Print();return 0;
}

在这里插入图片描述

  • C++11⽀持在成员变量声明的位置给缺省值,注意:这个缺省值只是是给没有显⽰在初始化列表初始化的成员使⽤的。
  • 尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化。如果你没有给缺省值,对于没有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构造会编译错误。

示例:

class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};class Date
{
public:Date():_month(2){cout << "Date()" << endl;}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}
private:// 注意这⾥不是初始化,这⾥给的是缺省值,这个缺省值是给初始化列表的// 如果初始化列表没有显⽰初始化,默认就会⽤这个缺省值初始化int _year = 1;int _month = 1;int _day;Time _t = 1;const int _n = 1;int* _ptr = (int*)malloc(12);
};
int main()
{Date d1;d1.Print();return 0;
}
  • 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆关。建议声明顺序和初始化列表顺序保持⼀致。

示例:下⾯程序的运⾏结果是什么()
A. 输出 1 1
B. 输出 2 2
C. 编译报错
D. 输出 1 随机值
E. 输出 1 2
F. 输出 2 1

class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2 = 2;int _a1 = 2;
};
int main()
{A aa(1);aa.Print();
}

在这里插入图片描述
所以这道题应该选D,这道题还是很重要的。

3.2 类型转换

  • C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数
  • 构造函数前⾯加explicit就不再⽀持隐式类型转换

示例:

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的临时对象,再用这个临时对象拷贝构造aa1// 编译器优化:遇到连续构造+拷贝构造 -> 优化为直接构造A aa1 = 1;aa1.Print();const A& aa2 = 1;// C++11之后开始支持多参数转化A aa3 = { 2, 2 };return 0;
}

3.3 static成员

  • ⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。

示例:

class A
{
private:// 类内声明static int _scount;
};// 类外初始化
int A::_scount = 0;
  • 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。

示例:对于上面的示例中,我们计算类A的大小:cout << sizeof(A) << endl; 输出的结果是1,之前我们讲过1是为了占位使用的。

  • ⽤static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。
  • 静态成员函数中可以访问其他的静态成员,但是不能访问非静态的,因为没有this指针

示例:

在这里插入图片描述

  • 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。
  • 突破类域就可以访问静态成员,可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。
  • 静态成员也是类的成员,受public、protected、private 访问限定符的限制。
  • 注意:静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。

示例:实现一个类,计算程序共创建了多少个类对象

class A
{
public:A(){++_scount;}A(const A& a){++_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;
}

在这里插入图片描述
牛客网的一个例题,不允许使用各种循环和递归,实现 1 + 2 + 3 + … + n ?

我们可以通过创建类来实现,创建第几个类就让他加上几。示例:

class Sum
{
public:Sum(){_ret += _i;++_i;}static int GetRet(){return _ret;}
private:static int _i;static int _ret;
};int Sum::_i = 1;
int Sum::_ret = 0;class Solution
{
public:int Sum_Solution(int n) {//VS不支持边长数组,会报错Sum arr[n];return Sum::GetRet();}
};

注意:VS不支持边长数组。
加粗样式
例题:有A、B、C、D四个类

C c;
int main()
{A a;B b;static D d;return 0}

A:D B A C
B:B A D C
C:C D B A
D:A B D C
E:C A B D
F:C D A B

Q1:程序中A,B,C,D构造函数调用顺序为?(E)
A1:这个很简单
Q2程序中A,B,C,D析构函数调⽤顺序为?(B)
A2:这里要注意一点,static修饰的变量是存放在静态区的,static修饰的变量生命周期会变长,即整个main函数栈帧销毁才会销毁D,所以辉县析构B和A,在析构D,由于C是在全局变量中,所以最后析构他(它是最先创建的,先创建的后析构)

3.4 友元

  • 友元提供了⼀种突破类访问限定符封装的方式,友元分为:友元函数和友元类,在函数声明或者类声明的前⾯加friend(没有要求,可放在public中也可以放在private中),并且把友元声明放到⼀个类的里面。
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  • 外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。
  • ⼀个函数可以是多个类的友元函数。
  • 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。
  • 友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。
  • 友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是B的友元。
  • 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

友元函数示例:

// 前置声明,否则A的友元函数声明编译器不认识B
class B;class A
{// 友元声明friend void func(const A& aa, const B& bb);
private:int _a1 = 1;int _a2 = 2;
};class B
{// 友元声明friend void func(const A& aa, const B& bb);
private:int _b1 = 3;int _b2 = 4;
};void func(const A& aa, const B& bb)
{cout << aa._a1 << endl;cout << bb._b1 << endl;
}int main()
{A aa;B bb;func(aa, bb);return 0;
}

友元类示例:

class A
{// 友元声明friend class B;
private:int _a1 = 1;int _a2 = 2;
};class B
{
public:void func1(const A& aa){cout << aa._a1 << endl;cout << _b1 << endl;}void func2(const A& aa){cout << aa._a2 << endl;cout << _b2 << endl;}
private:int _b1 = 3;int _b2 = 4;
};
int main()
{A aa;B bb;bb.func1(aa);bb.func2(aa);return 0;
}

3.5 内部类

  • 如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类,跟定义在全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。
  • 内部类默认是外部类的友元类
  • 内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。

示例:

class A
{
public:class B //B默认就是A的友元{public:void func(const A& a){cout << _k << ' ' << a.h << endl;}};
private:static int _k;int h = 1;
};int A::_k = 1;int main()
{//输出结果是4,所以内部类是不占空间的cout << sizeof(A) << endl;A::B b; //实例化BA aa;b.func(aa);return 0;
}

我们把上面那个牛客网的题目优化一下:

class Solution
{
public:class Sum{Sum(){_ret += _i;_i++;}};
public:int Sum_Solution(int n){// 变长数组Sum arr[n];return _ret;}
private:static int _i;static int _ret;
};int Solution::_i = 1;
int Solution::_ret = 0;

这样写是不是更简单、优美了。

3.6 匿名对象

  • 用类型(实参) 定义出来的对象叫做匿名对象,相比之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。
  • 匿名对象⽣命周期只在当前⼀行,⼀般临时定义⼀个对象当前用⼀下即可,就可以定义匿名对象。

示例:

class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};class Solution
{
public:int Sum_Solution(int n) {return n;}
};int main()
{A aa1;//不可以这样定义对象,因为编译器⽆法识别下⾯是⼀个函数声明,还是对象定义//这里VS没有报错,也没有调用它的构造和析构函数,说明编译器把它当做是函数声明//A aa2();//但是我们可以这么定义匿名对象,匿名对象的特点不⽤取名字//但是他的⽣命周期只有这⼀⾏,我们可以看到下⼀⾏他就会⾃动调⽤析构函数A();A(1);// 匿名对象在这样场景下就很好⽤,当然还有⼀些其他使⽤场景Solution().Sum_Solution(10);return 0;
}

3.7 对象拷贝时的编译器优化

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

这一点未完待续!!!

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

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

相关文章

<数据集>路面坑洼识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;665张 标注数量(xml文件个数)&#xff1a;665 标注数量(txt文件个数)&#xff1a;665 标注类别数&#xff1a;1 标注类别名称&#xff1a;[pothole] 序号类别名称图片数框数1pothole6651740 使用标注工具&#x…

Oracle篇—通过官网下载最新的数据库软件或者历史数据库软件

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

dns实验3:主从同步-完全区域传输

服务器192.168.234.111&#xff08;主服务器&#xff09;&#xff0c;打开配置文件&#xff1a; 打开配置文件&#xff1a; 关闭防火墙&#xff0c;改宽松模式&#xff1a; 重启服务&#xff1a; 服务器192.168.234.112&#xff08;从服务器&#xff09;&#xff0c;打开配置文…

OpenCV圆形标定板检测算法findCirclesGrid原理详解

OpenCV的findCirclesGrid函数检测圆形标定板的流程如下:   findCirclesGrid函数源码: //_image,输入图像 //patternSize,pattern的宽高 //_centers,blobs中心点的位置 //flags,pattern是否对称 //blobDetector,这里使用的是SimpleBlobDetector bool cv::findCirclesGrid(…

Java - JSR223规范解读_在JVM上实现多语言支持

文章目录 1. 概述2. 核心目标3. 支持的脚本语言4. 主要接口5. 脚本引擎的使用执行JavaScript脚本执行groovy脚本1. Groovy简介2. Groovy脚本示例3. 如何在Java中集成 Groovy4. 集成注意事项 6. 与Java集成7. 常见应用场景8. 优缺点9. 总结 1. 概述 JSR223&#xff08;Java Spe…

自然语言处理:基于BERT预训练模型的中文命名实体识别(使用PyTorch)

命名实体识别&#xff08;NER&#xff09; 命名实体识别&#xff08;Named Entity Recognition, NER&#xff09;是自然语言处理&#xff08;NLP&#xff09;中的一个关键任务&#xff0c;其目标是从文本中识别出具有特定意义的实体&#xff0c;并将其分类到预定义的类别中。这…

【C++】数组

1.概述 所谓数组&#xff0c;就是一个集合&#xff0c;该集合里面存放了相同类型的数据元素。 数组特点&#xff1a; &#xff08;1&#xff09;数组中的每个数据元素都是相同的数据类型。 &#xff08;2&#xff09;数组是有连续的内存空间组成的。 2、一维数组 2.1维数组定…

微软表示不会使用你的 Word、Excel 数据进行 AI 训练

​微软否认使用 Microsoft 365 应用程序&#xff08;包括 Word、Excel 和 PowerPoint&#xff09;收集数据来训练公司人工智能 (AI) 模型的说法。 此前&#xff0c;Tumblr 的一篇博文声称&#xff0c;雷德蒙德使用“互联体验”功能抓取客户的 Word 和 Excel 数据&#xff0c;用…

leetcode--螺旋矩阵

LCR 146.螺旋遍历二维数组 给定一个二维数组 array&#xff0c;请返回「螺旋遍历」该数组的结果。 螺旋遍历&#xff1a;从左上角开始&#xff0c;按照 向右、向下、向左、向上 的顺序 依次 提取元素&#xff0c;然后再进入内部一层重复相同的步骤&#xff0c;直到提取完所有元…

C++ 分治

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 1.分治法 2.二分搜索 函数传参——数组 3.棋盘覆盖 4.合并排序 5.快速排序 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 1.分治法 基…

Spark常问面试题---项目总结

一、数据清洗&#xff0c;你都清洗什么&#xff1f;或者说 ETL 你是怎么做的&#xff1f; 我在这个项目主要清洗的式日志数据&#xff0c;日志数据传过来的json格式 去除掉无用的字段&#xff0c;过滤掉json格式不正确的脏数据 过滤清洗掉日志中缺少关键字段的数据&#xff…

基于智能语音交互的智能呼叫中心工作机制

在智能化和信息化不断进步的现代&#xff0c;智能呼叫中心为客户提供高质量、高效率的服务体验&#xff0c;提升众多品牌用户的满意度和忠诚度。作为实现智能呼叫中心的关键技术之一的智能语音交互技术&#xff0c;它通过集成自然语言处理&#xff08;NLP&#xff09;、语音识别…

Android Studio 右侧工具栏 Gradle 不显示 Task 列表

问题&#xff1a; android studio 4.2.1版本更新以后AS右侧工具栏Gradle Task列表不显示&#xff0c;这里需要手动去设置 解决办法&#xff1a; android studio 2024.2.1 Patch 2版本以前的版本设置&#xff1a;依次打开 File -> Settings -> Experimental 选项&#x…

SpringBoot集成Kafka和avro和Schema注册表

Schema注册表 为了提升kafka的性能&#xff0c;减少网络传输和存储的数据大小&#xff0c;可以把数据的schema部分单独存储到外部的schema注册表中&#xff0c;整体架构如下图所示&#xff1a; 1&#xff09;把所有数据需要用到的 schema 保存在注册表里&#xff0c;然后在记…

http(请求方法,状态码,Cookie与)

目录 1.http中常见的Header(KV结构) 2.http请求方法 2.1 请求方法 2.2 telnet 2.3 网页根目录 2.3.1 概念 2.3.2 构建一个首页 2.4 GET与POST方法 2.4.1 提交参数 2.4.2 GET与POST提交参数对比 2.4.3 GET和POST对比 3.状态码 3.1 状态码分类 3.2 3XXX状态码 3.2 …

十,[极客大挑战 2019]Secret File1

点击进入靶场 查看源代码 有个显眼的紫色文件夹&#xff0c;点击 点击secret看看 既然这样&#xff0c;那就回去查看源代码吧 好像没什么用 抓个包 得到一个文件名 404 如果包含"../"、"tp"、"input"或"data"&#xff0c;则输出"…

pytest自定义命令行参数

实际使用场景&#xff1a;pytest运行用例的时候&#xff0c;启动mitmdump进程试试抓包&#xff0c;pytest命令行启动的时候&#xff0c;传入mitmdump需要的参数&#xff08;1&#xff09;抓包生成的文件地址 &#xff08;2&#xff09;mitm的proxy设置 # 在pytest的固定文件中…

Unity AssetBundles(AB包)

目录 前言 AB包是什么 AB包有什么作用 1.相对Resources下的资源AB包更好管理资源 2.减小包体大小 3.热更新 官方提供的打包工具:Asset Bundle Browser AB包资源加载 AB包资源管理模块代码 前言 在现代游戏开发中&#xff0c;资源管理是一项至关重要的任务。随着游戏内容…

(一)Linux下安装NVIDIA驱动(操作记录)

目录 一、查看CUDA版本 1.输入nvidia-smi&#xff0c;查看驱动支持的最大CUDA版本&#xff0c;这里是11.6 2.输入nvcc --version&#xff0c;查看当前安装的CUDA版本&#xff0c;这里是11.3 二、卸载旧的NVIDIA驱动 1.卸载原有驱动 2.禁用nouveau&#xff08;必须&#x…

用Python做数据分析环境搭建及工具使用(Jupyter)

目录 一、Anaconda下载、安装 二、Jupyter 打开 三、Jupyter 常用快捷键 3.1 创建控制台 3.2 命令行模式下的快捷键 3.3 运行模式下快捷键 3.4 代码模式和笔记模式 3.5 编写Python代码 一、Anaconda下载、安装 【最新最全】Anaconda安装python环境_anaconda配置python…