【c++】类和对象 (中) (类的默认成员函数)

类的默认成员函数

在C++中,如果你定义了一个类但没有显式地提供特定的成员函数(比如构造函数、析构函数、拷贝构造函数、拷贝赋值运算符等),编译器会为这些函数生成默认的实现。这些默认生成的成员函数称为类的默认成员函数。那么既然编译器会默认生成,那么我们学习什么呢?

第一:我们要能判断默认生成的函数能否则满足我们的需求

第二:如果默认生成的函数不能满足我们的需求,那么我们该如何实现这些函数

 实际上是八个,后面的后续补充。接下来我们依次来学习这些函数。

构造函数 

构造函数是特殊的成员函数,需要注意的是,构造函数完成的并不是在内存中开空间的过程。当创建一个类的对象时,系统会为这个对象分配一块内存空间,以存储对象的数据成员。接下来才会调用构造函数,用来完成初始化这个对象,使申请的内存处于一个可用的状态。构造函数完美的替代了以前用c语言实现数据结构时用来初始化的Init。

构造函数的特点:

1. 函数名与类名相同。

2. 无返回值。(返回值啥都不需要给,也不需要写void,不要纠结,C++规定如此)

3. 对象实例化时系统会自动调用对应的构造函数。

4. 构造函数可以重载。

5. 如果类中没有显式定义构造函数,则C++编译器会自动生成⼀个无参的默认构造函数,⼀旦用户显式定义编译器将不再生成。

6. 无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函 数。但是这三个函数有且只有⼀个存在,不能同时存在。无参构造函数和全缺省构造函数虽然构成 函数重载,但是调用时会存在歧义。要注意很多同学会认为默认构造函数是编译器默认生成那个叫默认构造,实际上无参构造函数、全缺省构造函数也是默认构造,总结⼀下就是不传实参就可以调用的构造就叫默认构造。

7. 我们不写,编译器默认生成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始 化是不确定的,看编译器。对于自定义类型成员变量,要求调用这个成员变量的默认构造函数初始 化。如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要用初始化列表才能解决,初始化列表,我们下个章节再细细讲解。

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}// ...private:STDataType* _a;size_t _capacity;size_t _top;
};
// 两个Stack实现队列class MyQueue
{
public://编译器默认生成MyQueue的构造函数调⽤了Stack的构造,完成了两个成员的初始化private:Stack pushst;Stack popst;
};
int main()
{MyQueue mq;return 0;
}

对自定义的成员变量会调用这个成员变量的默认构造。

如果这个成员变量没有默认构造就会报错 

同时要注意对内置类型的处理c++标准没有规定,不同编译器处理的不同,为了规避错误,我们要自己手动处理内置类型。 

接下来我们来手动的实现几个构造函数:

无参的构造函数

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;//创建一个类Dateclass Date
{
public:// 1.无参构造函数Date(){_year = 1;_month = 1;_day = 1;}void print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;d1.print();return 0;
}

在监视窗口可以看到在实例化对象之后,构造函数已经被自动调用了。 

下面的是用c语言实现的链表的初始化,相比之下我们可以发现c++中的构造函数并不需要显式的调用 

带参构造函数

#include <iostream>
using namespace std;//创建一个类Dateclass Date
{
public:// 1.无参构造函数Date(){_year = 1;_month = 1;_day = 1;}//2.带参的构造函数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;
};int main()
{/*Date d1;d1.print();*/Date d2(2024, 8, 8);d2.print();return 0;
}

相比于无参的构造函数,带参的构造函数能够在初始化的时候手动设置初始化的数据,具有更高的自由度。

全缺省构造函数


#include <iostream>
using namespace std;//创建一个类Dateclass Date
{
public:// 1.无参构造函数//Date()//{//	_year = 1;//	_month = 1;//	_day = 1;//}//2.带参的构造函数/*Date(int year, int month, int day){_year = year;_month = month;_day = day;}*///3.全缺省的构造函数Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{/*Date d1;d1.print();*//*Date d2(2024, 8, 8);d2.print();*/Date d3(2024);d3.print();return 0;
}

需要注意,全缺省构造函数和无参构造函数虽然构成函数重载,但是在不传入参数时会产生调用歧义,所以不能同时存在。全缺省和带参的构造函数只是默认参数的差别,不构成函数重载。

析构函数 

析构函数与构造函数功能相反,析构函数不是完成对对象本⾝的销毁,比如局部对象是存在栈帧的, 函数结束栈帧销毁,他就释放了,不需要我们管,C++规定对象在销毁时会自动调用析构函数,完成对 象中资源的清理释放工作。析构函数的功能类比我们之前Stack实现的Destroy功能,而像Date没有 Destroy,其实就是没有资源需要释放,所以严格说Date是不需要析构函数的。

析构函数的特点:

1. 析构函数名是在类名前加上字符~。

2. 无参数无返回值。(这里跟构造类似,也不需要加void)

3. ⼀个类只能有⼀个析构函数。若未显式定义,系统会自动生成默认的析构函数。

4. 对象生命周期结束时,系统会自动调用析构函数。

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}~Stack(){free(_a);_a = nullptr;_top = _capacity = 0;}private:STDataType* _a;size_t _capacity;size_t _top;
};
// 两个Stack实现队列class MyQueue
{
public://编译器默认生成MyQueue的构造函数调用了Stack的构造,完成了两个成员的初始化private:Stack pushst;Stack popst;
};
int main()
{Stack str1;return 0;
}

5. 跟构造函数类似,我们不写编译器自动生成的析构函数对内置类型成员不做处理,自定类型成员会调用他的析构函数。

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}~Stack(){free(_a);_a = nullptr;_top = _capacity = 0;}private:STDataType* _a;size_t _capacity;size_t _top;
};
// 两个Stack实现队列class MyQueue
{
public://编译器默认生成MyQueue的构造函数调用了Stack的构造,完成了两个成员的初始化private:Stack pushst;Stack popst;
};
int main()
{MyQueue mq;return 0;
}

6. 还需要注意的是我们显示写析构函数,对于自定义类型成员也会调用他的析构,也就是说自定义类 型成员无论什么情况都会自动调用析构函数。

7. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,如Date;如果默认生成的析构就可以用,也就不需要显示写析构,如MyQueue;但是有资源申请时,⼀定要自己写析构,否则会造成资源泄漏,如Stack。

8. ⼀个局部域的多个对象,C++规定后定义的先析构。

拷贝构造函数

如果⼀个构造函数的第⼀个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数 也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数。

拷贝构造的特点:

1. 拷贝构造函数是构造函数的⼀个重载。

2. 拷贝构造函数的第一个参数必须是类类型对象的引用,使用传值方式编译器直接报错,因为语 法逻辑上会引发无穷递归调用。

3. C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返 回都会调用拷贝构造完成。

4. 若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。

5. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的拷⻉构造就可以完 成需要的拷贝,所以不需要我们显⽰实现拷贝构造。像Stack这样的类,虽然也都是内置类型,但 是_a指向了资源,编译器⾃动⽣成的拷贝构造完成的值拷贝/浅拷贝不符合我们的需求,所以需要 我们⾃⼰实现深拷贝(对指向的资源也进行拷贝)。像MyQueue这样的类型内部主要是⾃定义类型 Stack成员,编译器自动生成的拷贝构造会调用Stack的拷贝构造,也不需要我们显⽰实现 MyQueue的拷贝构造。这里还有⼀个⼩技巧,如果⼀个类显⽰实现了析构并释放资源,那么他就 需要显示写拷贝构造,否则就不需要。

6. 传值返回会产生⼀个临时对象调用拷贝构造,传值引用返回,返回的是返回对象的别名(引用),没 有产生拷贝。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使用引用返回是有问题的,这时的引用相当于⼀个野引用,类似⼀个野指针⼀样。传引用返回可以减少拷贝,但是⼀定要确保返回对象,在当前函数结束后还在,才能用引用返回。

接下来我们根据上述特点来自己实现一下拷贝构造函数:

#define _CRT_SECURE_NO_WARNINGS 1#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(const Date& d){_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;};void Func1(Date d)
{cout << &d << endl;
}int main()
{Date d1(2024, 8, 11);Date d2(d1);d1.Print();d2.Print();return 0;
}

执行结果:

 拷贝构造函数是构造函数的重载,可以通过已经存在的对象来初始化新开的对象。

和构造函数一样,如果没有显示定义拷贝构造函数,编译器会自动生成,与默认生成的构造函数不同的是,自动生成的拷贝构造函数会对内置类型进行处理,会对内置类型进行浅拷贝/值拷贝。

#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(const Date& d){_year = d._year;_month = d._month;_day = d._day;}*/void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;};void Func1(Date d)
{cout << &d << endl;
}int main()
{Date d1(2024, 8, 11);Date d2(d1);d1.Print();d2.Print();return 0;
}

 但是默认生成的拷贝构造函数只能进行值拷贝

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}~Stack(){free(_a);_a = nullptr;_top = _capacity = 0;}private:STDataType* _a;size_t _capacity;size_t _top;
};
class MyQueue
{
public:private:Stack pushst;Stack popst;
};
int main()
{Stack s1;Stack s2(s1);return 0;
}

 用编译器自动生成的拷贝构造函数初始化栈,s1和s2的地址也是完全一样的。析构的时候对同一块地址会析构两次,在第二次析构时,要通过this指针访问成员变量,但是这个时候this指针已经不能指向成员变量了(内存被释放了),会报错。

所以当对象指向资源时,我们要自己写拷贝构造函数 。

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}//手动实现深拷贝Stack(const Stack& s){_a = (STDataType*)malloc(sizeof(s._a) * s._capacity);//先开空间if (_a = nullptr){perror("malloc fail");return;}memcpy(_a, s._a, sizeof(STDataType) * s._top);_capacity = s._capacity;_top = s._top;}~Stack(){free(_a);_a = nullptr;_top = _capacity = 0;}private:STDataType* _a;size_t _capacity;size_t _top;
};
class MyQueue
{
public:private:Stack pushst;Stack popst;
};
int main()
{Stack s1;Stack s2(s1);return 0;
}

这样就不会出现地址相同,析构两次的错误。 

同样的,自定义类型的变量会自动调用它的析构函数。

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}//手动实现深拷贝Stack(const Stack& s){_a = (STDataType*)malloc(sizeof(s._a) * s._capacity);//先开空间if (_a = nullptr){perror("malloc fail");return;}memcpy(_a, s._a, sizeof(STDataType) * s._top);_capacity = s._capacity;_top = s._top;}~Stack(){free(_a);_a = nullptr;_top = _capacity = 0;}private:STDataType* _a;size_t _capacity;size_t _top;
};
class MyQueue
{
public:private:Stack pushst;Stack popst;
};
int main()
{/*Stack s1;Stack s2(s1);*/MyQueue m1;MyQueue m2(m1);return 0;
}

赋值运算符重载

运算符重载

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

• 运算符重载是具有特名字的函数,他的名字是由operator和后面要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。

• 重载运算符函数的参数个数和该运算符作用的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,二元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第二个参数。

• 如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算 符重载作为成员函数时,参数比运算对象少⼀个。


//运算符重载
#include <iostream>
using namespace std;
class Date
{
public:Date(int year = 1,int month = 1,int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << _month << _day << endl;}bool operator ==(Date x1){return _year == x1._year&& _month == x1._month && _day == x1._day;}private:int _year;int _month;int _day;
};int main()
{Date d1(2049);Date d2(2052);d1.operator== (d2);return 0;
}

• 运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。

• 不能通过连接语法中没有的符号来创建新的操作符:比如operator@。

.*     ::     sizeof      ?:      .  注意以上5个运算符不能重载。(选择题里面常考,大家要记⼀下)介绍一下.*

#include <iostream>class A {
public:void foo() { std::cout << "foo" << std::endl; }
};typedef void(A::*PF)(); // 定义了一个指向A类成员函数的指针类型,指向无参数且返回void的函数int main() {A a;                // 创建类A的对象PF p = &A::foo;     // p是指向A::foo的成员函数指针,c++规定要加&才能取到函数指针(a.*p)();           // 调用a对象的foo成员函数,等同于a.foo()return 0;
}

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

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

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

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

赋值运算符重载 

赋值运算符重载是一个默认成员函数,用于完成两个已存在的对象的拷贝赋值。注意与拷贝构造函数区分,赋值运算符重载是用于两个已存在的对象之间的拷贝赋值;拷贝构造函数是用已经存在的对象来初始化新的对象。

赋值运算符重载的特点:

1. 赋值运算符重载是⼀个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成 const 当前类类型引用,否则会传值传参会有拷贝。

2. 有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值目的是为了支持连续赋值场景。

3. 没有显式实现时,编译器会自动生成⼀个默认赋值运算符重载,默认赋值运算符重载行为跟默认拷贝构造函数类似,对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型 成员变量会调用他的赋值重载。 (这里和拷贝构造函数是相似的,如果显示实现了析构函数,对象指向了资源就需要自己手动实现赋值运算符重载)

4. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的赋值运算符重载就 可以完成需要的拷贝,所以不需要我们显⽰实现赋值运算符重载。像Stack这样的类,虽然也都是 内置类型,但是_a指向了资源,编译器自动生成的赋值运算符重载完成的值拷贝/浅拷贝不符合我 们的需求,所以需要我们自己实现深拷贝(对指向的资源也进行拷贝)。像MyQueue这样的类型内部 主要是⾃定义类型Stack成员,编译器自动生成的赋值运算符重载会调⽤Stack的赋值运算符重载, 也不需要我们显⽰实现MyQueue的赋值运算符重载。这⾥还有⼀个⼩技巧,如果⼀个类显⽰实现 了析构并释放资源,那么他就需要显⽰写赋值运算符重载,否则就不需要。

接下来我们来实现一下:

#include <iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//赋值运算符重载void operator = (const Date& d)//可以传参,用const传引用不用调用拷贝构造,节省时间{_year = d._year;_month = d._month;_day = d._day;}//拷贝构造Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << _year << _month << _day << endl;}bool operator ==(Date x1){return _year == x1._year&& _month == x1._month&& _day == x1._day;}private:int _year;int _month;int _day;
};int main()
{Date d1(2049);Date d2(2052);//赋值重载拷贝d2 = d1;//拷贝构造函数Date d3 = d2;Date d4(d2);return 0;
}

但是这样实现的函数没有返回值,不能够实现连续赋值。为了能够实现连续赋值,我们可以这样写:

#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 = (const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}//拷贝构造Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << _year << _month << _day << endl;}bool operator ==(Date x1){return _year == x1._year&& _month == x1._month&& _day == x1._day;}private:int _year;int _month;int _day;
};int main()
{Date d1(2049);Date d2(2052);//赋值重载拷贝d2 = d1;//拷贝构造函数Date d3 = d2;Date d4(d2);d1 = d2 = d3 = d4;return 0;
}

在这个函数执行完之后,this指针不会销毁。直接返回会形成一个拷贝,所以我们可以返回引用,用来提高效率。 

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

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

相关文章

C#学习笔记15:上位机助手_usercontrol窗体内嵌的应用

今日完善一下之前的上位机助手&#xff0c;做一个组合窗体内嵌的多功能助手软件应用, 与之前的上位机软件相比: 更注重控件能够随着窗体缩放而缩放变换&#xff0c;串口助手部分能自动后台检测串口设备&#xff0c;解决市面上大部分串口助手的打开初始化会卡顿的问题 ( 多线程后…

Linux服务管理-Nginx配置

静态解析主要解析html、css动态解析需要解析php 动态资源通过轮询分配到后端的Apache服务器处理 apache是同步阻塞&#xff0c;nginx是异步非阻塞

论文阅读笔记:Efficient Teacher: Semi-Supervised Object Detection for YOLOv5

Efficient Teacher: Semi-Supervised Object Detection for YOLOv5 1 背景1.1 动机1.2 问题 2 创新点3 方法4 模块4.1 伪标签分配4.2 Epoch Adapter 5 效果5.1 与SOTA方法对比5.2 消融实验 论文&#xff1a;https://arxiv.org/pdf/2302.07577v3.pdf 代码&#xff1a;https://g…

Python 常用内置函数

目录 1、enumerate函数 1.1、for循环中使用 1.2、enumerate指定索引的起始值 1.3、enumerate在线程中的作用 2、Map 函数 2.1、map()函数可以传多个迭代器对象 3、lambda表达式&#xff08;匿名函数&#xff09; 示例 4、sort函数和sorted函数 4.1、sort()函数 4.2、…

map和set的使用

关联式容器 在学习关联式容器之前&#xff0c;我们学习过的容器有vector、list、deque…这些容器称为序列式容器&#xff0c;单纯的存储数据存储的数据没有关联性。 即将学习的map 和set属于关联式容器&#xff0c;其里面存储的是<key, value>结构的键值对&#xff0c;…

制造知识普及(九)--企业内部物料编码(IPN)与制造商物料编码(MPN)

在日常的物料管理业务逻辑中&#xff0c;一物一码是物料管理的基本的业务规则&#xff0c;不管物料从产品开发还是仓库管理&#xff0c;甚至成本核算&#xff0c;都要遵循这个原则&#xff0c;才能保证产品数据的准确性&#xff0c;才具备唯一追溯的可行性。大部分企业都是这种…

某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏洞复现 [附POC]

文章目录 某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏…

C#数据类型转换

代码&#xff1a; using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace Test05 {class Program{static void Main(string[] args){double db 2008;//声明一个double类型变量db&#xff0c;并初始化为2008object obj db;//对db…

JAVA实现判断小程序用户是否关注公众号

本文主要描述了判断小程序用户是否关注公众号的逻辑实现及部分代码 首先阐述一下大致流程&#xff1a; 1、在将小程序和公众号绑定至同一个微信开发平台下&#xff1b; 2、后端拉取公众号已关注用户列表&#xff0c;并获取其中每一个用户的unionID&#xff0c; 建立已关注用户…

OCR调研

OCR调研 一、介绍 OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;是一种将图像中的文字转换为计算机可处理格式的技术。OCR技术经历了从传统OCR到基于深度学习的OCR的转变。深度学习OCR技术通过模拟人脑神经元结构处理文本和图像数据&am…

MATLAB - 强化学习(Reinforcement Learning)

系列文章目录 前言 一、什么是强化学习&#xff1f; 强化学习是一种以目标为导向的计算方法&#xff0c;计算机通过与未知的动态环境交互来学习执行任务。这种学习方法能让计算机在没有人工干预和明确编程的情况下&#xff0c;做出一系列决策&#xff0c;使任务的累积奖励最大化…

cmake 编译教程

参考链接&#xff1a;cmake使用详细教程&#xff08;日常使用这一篇就足够了&#xff09;_cmake教程-CSDN博客 一、只有一个源文件的程序编译 首先在当前目录下创建两个文件 hello.cpp CMakeLists.txt &#xff08;注意CMakeLists大小写&#xff0c;不要写错了&#xff09; …

推荐一个优秀的 .NET MAUI 组件库

目录 前言 组件介绍 组件展示 布局 按钮 复选框 进度条 导航栏 组件地址 最后 前言 .NET MAUI 的发布&#xff0c;项目中可以使用这个新的跨平台 UI 框架来轻松搭建的移动和桌面应用。 为了帮助大家更快地构建美观且功能丰富的应用&#xff0c;本文将推荐一款优秀…

AcCode核心思路

文章目录 在线OJ项目核心思路1. 项目介绍2.预备知识理解多进程编程为啥采用多进程而不使用多线程?标准输入&标准输出&标准错误 3.项目实现题目API实现相关实体类定义新增/修改题目获取题目列表 编译运行编译运行流程 4.统一功能处理 在线OJ项目核心思路 1. 项目介绍 …

有序转化数组(LeetCode)

题目 给你一个已经 排好序 的整数数组 和整数 、 、 。对于数组中的每一个元素 &#xff0c;计算函数值 &#xff0c;请 按升序返回数组 。 解题 在时间复杂度为解决问题 def sortTransformedArray(nums, a, b, c):def f(x):return a * x * x b * x cn len(nums)result…

4个从阿里毕业的P7打工人,当起了包子铺的老板

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247483727&idx1&sndb05d8c1115a4539716eddd9fde4e5c9&chksmc0e47813f793f105017fb8551c9b996dc7782987e19efb166ab665f44ca6d900210e6c4c0281&scene21#wechat_redirect 《网安面试指南》h…

学生公寓电费信息管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;公寓管理员管理&#xff0c;学生管理&#xff0c;楼层信息管理&#xff0c;用电情况管理&#xff0c;缴费清单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;用电情况…

【数据结构】六、图:4.图的遍历(深度优先算法DFS、广度优先算法BFS)

三、基本操作 文章目录 三、基本操作1.图的遍历1.1 深度优先遍历DFS1.1.1 DFS算法1.1.2 DFS算法的性能分析1.1.3 深度优先的生成树和生成森林 1.2 广度优先遍历BFS1.2.1 BFS算法1.2.2 BFS算法性能分析1.2.3 广度优先的生成树和生成森林 1.3 图的遍历与图的连通性 1.图的遍历 图…

Nginx系列-Nginx Location匹配规则

文章目录 Nginx系列-Nginx Location匹配规则1. 语法基础2. 匹配规则2.1 精确匹配&#xff08;&#xff09;2.2. 最长前缀匹配&#xff08;^~&#xff09;2.3. 正则表达式匹配&#xff08;~和~*&#xff09;2.4. 普通前缀匹配&#xff08;无修饰符&#xff09;2.5. 默认匹配&…

贷齐乐hpp+php特性注入

文章目录 运行过程waf第一层waf拦截第二层waf拦截 数据库查询语句注入思路注入 运行过程 foreach ($_REQUEST as $key > $value) {$_REQUEST[$key] dowith_sql($value);}$request_uri explode("?", $_SERVER[REQUEST_URI]);if (isset($request_uri[1])) {$rewr…