【C++】:类和对象(2)
朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux的基础知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!
C 语 言 专 栏:C语言:从入门到精通
数据结构专栏:数据结构
个 人 主 页 :stackY、
C + + 专 栏 :C++
Linux 专 栏 :Linux
目录
1. 类的6个默认成员函数
2. 构造函数
2.1概念
2.2特性
3. 析构函数
3.1概念
3.2特性
4. 拷贝构造
4.1概念
4.2特性
5. 赋值运算符重载
5.1运算符重载
5.2赋值运算符重载
5.3前置++、后置++重载
6. const成员
7. 取地址及const取地址操作符重载
1. 类的6个默认成员函数
如果一个类中什么成员都没有,简称为空类。空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。//空类 class Date {};
![]()
2. 构造函数
2.1概念
构造函数主要完成初始化工作
对于下面这个日期类:
class Date { public://初始化void Init(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, d2;d1.Init(2023, 10, 1);d1.Print();d2.Init(2023, 10, 2);d2.Print();return 0; }
对于Date类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
2.2特性
构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。其特征如下:1. 函数名与类名相同。2. 无返回值。3. 对象实例化时编译器自动调用对应的构造函数。4. 构造函数可以重载。class Date { public://带参的构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}//无参的构造函数Date(){}void Print(){cout << _year << "-" << _month << "-" << _day << endl;} private:int _year;int _month;int _day; };void TestDate() {Date d1; //调用无参的构造函数Date d2(2023, 10, 1);//调用带参的构造函数//Date d3(); //调用无参的构造函数创建对象时不能带(),否则就变成了函数声明 }
5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。class Date { public:/*//带参的构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}//无参的构造函数Date(){}*/void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day; };int main() {Date d1;return 0; }
当我们屏蔽掉我们自己写两个构造函数之后,在创建对象时会使用编译器自动生成的构造函数来完成对应的初始化,如果我们自己已经写了构造函数,则不再会自动生成。
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; };int main() {Date d1;Date d2(2023, 10, 1);return 0; }
6. 关于编译器生成的默认成员函数:不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的 默认构造函数并没有什么用??解答:由于C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char/int*/char*...,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数:class Time { public:Time(){_hour = 0;_minute = 0;_second = 0;} private:int _hour;int _minute;int _second; };class Date { private://内置类型int _year;int _month;int _day;//自定义类型Time _t; };int main() {Date d1;return 0; }
注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。class Time { public:Time(){_hour = 0;_minute = 0;_second = 0;} private:int _hour;int _minute;int _second; };class Date { private://内置类型//C++11支持在声明时给内置类型缺省值int _year = 1949;int _month = 10;int _day = 1;//自定义类型Time _t; };
为了代码的实用性。所以我们在写构造函数时写为全缺省是一种非常不错的选择,当我们进行无参创建时会自动使用我们给的缺省值,而并不是随机值。class Date { public://全缺省构造函数Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;} private://内置类型int _year;int _month;int _day; };int main() {Date d1;Date d2(2023, 10, 1);return 0; }
7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。多个并存就会产生调用二义性,不传参调用的就是默认构造class Date { public://全缺省构造函数Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}//无参构造函数Date(){_year = 0;_month = 0;_day = 0;} private://内置类型int _year;int _month;int _day; };int main() {Date d1;return 0; }
这段代码首先全缺省的构造函数和无参的构造函数形成了函数重载,但是在定义对象时进行了一个无参的调用,这时就会出现一个函数调用出现冲突的问题,由于是无参,既可以调用全缺省的,也可以调用午无参的,那么编译器就陷入了困难,所以尽量避免无参和全缺省的构造函数同时出现。
总结:
编译器生成的默认构造:
1. 我们不写,才会自动生成
2. 不会对内置类型进行处理(C++11支持对内置类型声明时给缺省值)
3. 自定义类型才会处理,会去调用这个成员的默认构造函数
当成员变量都是自定义类型时,可以考虑不写构造函数
3. 析构函数
3.1概念
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
3.2特性
1. 析构函数名是在类名前加上字符 ~。2. 无参数无返回值类型。3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。typedef int DateType; class Stack { public://构造函数Stack(size_t capacity){_array = (DateType*)malloc(sizeof(DateType) * capacity);if (_array == nullptr){perror("malloc fail");exit(-1);}_size = 0;_capacity = capacity;}void STPush(DateType x){//...}//析构函数~Stack(){free(_array);_array = nullptr;_size = _capacity = 0;} private:DateType* _array;size_t _capacity;size_t _size; };int main() {Stack st(1);return 0; }
5. 关于编译器自动生成的析构函数,是否会完成一些事情呢?我们可以采用程序来观察一下:typedef int DateType; class Stack { public://构造函数Stack(){_array = (DateType*)malloc(sizeof(DateType) * 4);if (_array == nullptr){perror("malloc fail");exit(-1);}_size = 0;_capacity = 4;}void STPush(DateType x){//...}private:DateType* _array;size_t _capacity;size_t _size; };int main() {Stack st;return 0; }
可以看到编译器默认生成的析构函数也是不会对内置类型做处理,那么当遇见自定义类型它会如何呢?
typedef int DateType; class Stack { public://构造函数Stack(){_array = (DateType*)malloc(sizeof(DateType) * 4);if (_array == nullptr){perror("malloc fail");exit(-1);}_size = 0;_capacity = 4;}void STPush(DateType x){//...}//析构函数~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;} private:DateType* _array;size_t _capacity;size_t _size; };class Date { public:Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}private://内置类型int _year;int _month;int _day;//自定义类型Stack st; }; int main() {//Stack st;Date d1;return 0; }
在这个过程中main函数 中创建了 Date 对象 d1 ,而 d1 中包含 4 个成员变量,其中 _year, _month, _day三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而st是Stack类对象,所以在d1销毁时,要将其内部包含的Stack类的st 对象销毁,所以要调用Stack类的析构函数。但是:main函数中不能直接调用Stack类的析构函数,实际要释放的是Date 类对象,所以编译器会调用 Date类的析构函数,而Date 没有显式提供,则编译器会给 Date类生成一个默认的析构函数,目的是在其内部调用Stack类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁main函数中并没有直接调用Stack类析构函数,而是显式调用编译器为Date 类生成的默认析构函数。注意:创建哪个类的对象则调用该类的构造函数,销毁那个类的对象则调用该类的析构函数
6. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。
4. 拷贝构造
4.1概念
在日常生活中,我们发现有两个人长得几乎一模一样,我们称他们为双胞胎,那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。
4.2特性
首先我们可以看这样一段代码:typedef int DateType; class Stack { public://构造函数Stack(size_t capacity = 3){cout << "Stack()" << endl;_array = (DateType*)malloc(sizeof(DateType) * capacity);if (_array == nullptr){perror("malloc fail");exit(-1);}_size = 0;_capacity = capacity;}//析构函数~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;} private:DateType* _array;size_t _capacity;size_t _size; };void func(Stack s) {//... }int main() {Stack s1;//函数调用进行了一份拷贝func(s1);return 0; }
首先这段代码是会报错的,因为s1是Stack类的对象,当func函数调用s1的时候,会拷贝一份s1,最主要的是拷贝的s与s1是同一块空间,就代表着两个类对象同时指向同一个空间,那么在进行析构函数清理资源的时候,无论先清理哪一个,剩下的一个指向的就是一块已经被释放的空间,就会对同一块空间进行多次释放,造成程序崩溃,那么就需要拷贝构造函数来解决这个问题:
拷贝构造函数也是特殊的成员函数,其特征如下:1. 拷贝构造函数是构造函数的一个重载形式。2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。class Date { public://构造函数Date(int year = 0, int month = 0, int day = 0){cout << "Date()" << endl;_year = year;_month = month;_day = day;}//拷贝构造//Date(const Date d) 不能使用传值调用Date(const Date& d){cout << "Date(const Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day;} private://内置类型int _year;int _month;int _day; }; int main() {Date d1;Date d2(d1);return 0; }
在这里说一下在传值调用的时候为什么会发生无穷递归:首先要明白一个点,传值就需要进行拷贝,拷贝就需要调用拷贝构造。
3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。class Date { public://构造函数Date(int year = 1949, int month = 10, int day = 1){cout << "Date()" << endl;_year = year;_month = month;_day = day;} private://内置类型int _year;int _month;int _day; }; int main() {Date d1;Date d2(d1);return 0; }
那么拷贝构造对于自定义类型如何呢?
class Time { public:Time(){_hour = 1;_minute = 1;_second = 1;} private:int _hour;int _minute;int _second; };class Date { public://构造函数Date(int year = 1949, int month = 10, int day = 1){cout << "Date()" << endl;_year = year;_month = month;_day = day;} private://内置类型int _year;int _month;int _day;//自定义类型Time _t; }; int main() {Date d1;Date d2(d1);return 0; }
注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式(浅拷贝)直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。
4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,如果没有资源的创建于释放是不需要自己写拷贝构造的,如果有资源的创建于释放是需要自己写。
typedef int DateType; class Stack { public://构造函数Stack(size_t capacity = 3){cout << "Stack()" << endl;_array = (DateType*)malloc(sizeof(DateType) * capacity);if (_array == nullptr){perror("malloc fail");exit(-1);}_size = 0;_capacity = capacity;} //析构函数~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;} private:DateType* _array;size_t _capacity;size_t _size; };int main() {Stack s1(4);Stack s2(s1);return 0; }
程序崩溃了,那么是什么原因呢?
由于编译器默认生成的拷贝构造函数都是浅拷贝(值拷贝),所以导致了s1和s2指向的是同一块空间,那么在进行s2的析构函数清理资源的时候,先清理了s2,所以s1和s2指向的这同一块空间已经被释放了,但是s1的析构函数并不知道,还会对这块空间进行释放,那么对同一块空间的多次释放就会造成程序崩溃。
注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
typedef int DateType; class Stack { public://构造函数Stack(size_t capacity = 3){cout << "Stack()" << endl;_array = (DateType*)malloc(sizeof(DateType) * capacity);if (_array == nullptr){perror("malloc fail");exit(-1);}_size = 0;_capacity = capacity;} //深拷贝//拷贝构造Stack(const Stack& s){cout << "Stack(const Stack& s)" << endl;_array = (DateType*)malloc(sizeof(DateType) * s._capacity);if (_array == nullptr){perror("malloc fail");exit(-1);}memcpy(_array, s._array, sizeof(DateType) * s._capacity);_size = s._size;_capacity = s._capacity;}//析构函数~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;} private:DateType* _array;size_t _capacity;size_t _size; };int main() {Stack s1(4);Stack s2(s1);return 0; }
5. 拷贝构造函数典型调用场景:
- 使用已存在对象创建新对象
- 函数参数类型为类类型对象
- 函数返回值类型为类类型对象
5. 赋值运算符重载
5.1运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。函数名字为:关键字operator后面接需要重载的运算符符号。函数原型:返回值类型 operator操作符(参数列表)注意:
- 不能通过连接其他符号来创建新的操作符:比如operator@
- 重载操作符必须有一个类类型参数
- 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
- 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
- .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。
1. 全局的运算符重载
//全局的operator== bool operator==(const Date& d1, const Date& d2) {return d1._year == d2._year&& d1._month == d2._month&& d1._day == d2._day; }//全局的operator!= bool operator!=(const Date& d1, const Date& d2) {return !(d1 == d2); }//全局的operator< bool operator<(const Date& d1, const Date& d2) {if (d1._year < d2._year){return true;}else if (d1._year == d2._year && d1._month < d2._month){return true;}else if (d1._year == d2._year && d1._month == d2._month && d1._day < d2._day){return true;}else{return false;} }//全局的operator<= bool operator<=(const Date& d1, const Date& d2) {return d1 < d2 || d1 == d2; }//全局的operator> bool operator>(const Date& d1, const Date& d2) {return !(d1 <= d2); }//全局的operator>= bool operator>=(const Date& d1, const Date& d2) {return !(d1 < d2); }//获取天数 int GetMonth_day(int year, int month) {int monthArray[13] = { 0,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 monthArray[month]; }//全局的operator+= Date& operator+=(Date& d, int day) {d._day += day;while (d._day > GetMonth_day(d._year, d._month)){//天满了进月d._day -= GetMonth_day(d._year, d._month);d._month++;//月满了进年,月置为1if (d._month == 13){++d._year;d._month = 1;}}return d; }//全局的operator+ Date operator+(Date& d, int day) {Date tmp(d);tmp += day;return tmp; }
2. 成员函数的运算符重载
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
class Date { public://全缺省构造函数Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}///运算符重载///成员函数operator==bool operator==(const Date& d){return _year == d._year&& _month == d._month&& _day == d._day;}//成员函数operator!=bool operator!=(const Date& d){return !(*this == d);}//成员函数operator<bool 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 && _day < d._day){return true;}else{return false;}}//成员函数operator<=bool operator<=(const Date& d){return *this < d || *this == d;}//成员函数operator>bool operator>(const Date& d){return !(*this <= d);}//成员函数operator>=bool operator>=(const Date& d){return !(*this < d);}//获取天数int GetMonth_day(int year, int month){int monthArray[13] = { 0,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 monthArray[month];}//成员函数operator+=Date& operator+=(int day){_day += day;while (_day > GetMonth_day(_year, _month)){//天满了进月_day -= GetMonth_day(_year, _month);_month++;//月满了进年,月置为1if (_month == 13){++_year;_month = 1;}}return *this;}//成员函数operator+Date operator+(int day){Date tmp(*this);tmp += day;return tmp;} private: int _year;int _month;int _day; };
5.2赋值运算符重载
1. 赋值运算符重载格式
①参数类型:const T&,传递引用可以提高传参效率
②返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测③是否自己给自己赋值④返回*this :要复合连续赋值的含义
class Date { public://全缺省构造函数Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}//成员函数operator=Date& operator=(const Date& d){//自己不能给自己赋值if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;} private: int _year;int _month;int _day; };
2. 赋值运算符只能重载成类的成员函数不能重载成全局函数
class Date { public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int _year;int _month;int _day; }; // 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数 Date& operator=(Date& left, const Date& right) {if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left; } // 编译失败: // error C2801: “operator =”必须是非静态成员
原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。
3. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
class Time { public:Time(){_hour = 1;_minute = 1;_second = 1;}Time& operator=(const Time& t){if (this != &t){_hour = t._hour;_minute = t._minute;_second = t._second;}return *this;} private:int _hour;int _minute;int _second; }; class Date1 { private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t; }; int main() {Date1 d1;Date1 d2;d1 = d2;return 0; }
既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?
如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要自己实现。
5.3前置++、后置++重载
根据前置++和后置++的区别:先使用后++还是先++后使用可以来进行设计:
1. 前置++
class Date { public://全缺省构造函数Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}//成员函数operator++(前置)Date& operator++(){_day += 1;return *this;}private: int _year;int _month;int _day; };
前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1
2. 后置++
class Date { public://全缺省构造函数Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}//成员函数operator++(后置)Date operator++(int){Date tmp(*this);_day += 1;return tmp;} private: int _year;int _month;int _day; };
6. const成员
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
class Date { public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << "Print()" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}void Print() const{cout << "Print()const" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;} private:int _year; // 年int _month; // 月int _day; // 日 }; void Test() {Date d1(2023, 1, 1);d1.Print();const Date d2(2023, 1, 1);d2.Print(); }int main() {Test();return 0; }
1. const对象可以调用非const成员函数吗?
不能,const对象权限小于非const对象,权限不能放大。
2. 非const对象可以调用const成员函数吗?可以,权限缩小。
3. const成员函数内可以调用其它的非const成员函数吗?不能,const成员函数它承诺不会修改对象的状态。因此,const成员函数不能调用非const成员函数,因为非const成员函数可以修改对象的状态,权限的放大。
4. 非const成员函数内可以调用其它的const成员函数吗?
非const成员函数内可以调用其它的const成员函数。非const成员函数没有限制对对象的修改,因此可以调用const成员函数,而const成员函数不会修改对象的状态,与非const成员函数的调用不冲突。这种情况下,调用const成员函数不会违反const成员函数的承诺。
7. 取地址及const取地址操作符重载
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
class Date { public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print() const{cout << "Print()const" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}//非const版本Date* operator&(){return this;}//const版本const Date* operator&()const{return this;}private:int _year; // 年int _month; // 月int _day; // 日 };
朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!
相关文章:

【C++】:类和对象(2)
朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux的基础知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数…...
【GIT版本控制】--提交更改
一、添加文件到暂存区 在GIT中,要提交更改,首先需要将文件添加到暂存区(Staging Area)。这是一个用于存放将要提交的更改的临时区域。以下是将文件添加到暂存区的步骤: 打开终端或命令提示符:首先&#x…...

解决高分屏DPI缩放PC端百度网盘界面模糊的问题
第一步 更新最新版本 首先,在百度网盘官网下载最新安装包: https://pan.baidu.com/download 进行覆盖安装 第二步 修改兼容性设置 右键百度网盘图标,点击属性,在兼容性选项卡中点击更改所有用户的设置 弹出的选项卡中选择更改高…...

全能视频工具 VideoProc Converter 4K for mac中文
VideoProc 4K提供快速完备的4K影片处理方案,您可以透过这款软体调节输出影片格式和大小。能够有效压缩HD/4K影片体积90%以上,以便更好更快地上传到YouTube,或是通过电子邮件附件发送。业界领先的视讯压缩引擎,让你轻松处理大体积视…...

Vue中实现自定义编辑邮件发送到指定邮箱(纯前端实现)
formspree里面注册账号 注册完成后进入后台新建项目并且新建表单 这一步完成之后你将得到一个地址 最后就是在项目中请求这个地址 关键代码如下: submitForm() {this.fullscreenLoading true;this.$axios({method: "post",url: "https://xxxxxxx…...

计算机专业毕业设计项目推荐11-博客项目(Go+Vue+Mysql)
博客项目(GoVueMysql) **介绍****系统总体开发情况-功能模块****各部分模块实现** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较了解计算机专业的毕业设计流程以及模式&am…...
QT实现TCP
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//实例化一个服务器server new QTcpServer(this);// 此时,服务器已经成功进入监听状态,…...

PostgreSQL ash —— pgsentinel插件
一、 插件作用 众所周知,pg是没有像oracle那样的ash视图的,因此要回溯历史问题不太方便。pgsentinel插件会将pg_stat_activity与pg_stat_statements视图内容定期快照,并存入pg_active_session_history和pg_stat_statements_history视图中。 1…...

【刷题笔记10.5】LeetCode:排序链表
LeetCode:排序链表 一、题目描述 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 二、分析 这题咱们默认要求:空间复杂度为O(1)。所以这把咱们用自底向上的方法实现归并排序,则可以达到O(1) 的空间复杂…...

三、【色彩模式与颜色填充】
文章目录 Photoshop常用的几种颜色模式包括:1. RGB模式2. CMYK模式3. 灰度模式4. LAB模式5. 多通道模式 Photoshop颜色填充1.色彩基础2.拾色器认识3.颜色填充最后附上流程图: Photoshop常用的几种颜色模式包括: 1. RGB模式 详细可参考&…...

karmada v1.7.0安装指导
前言 安装心得 经过多种方式操作,发现二进制方法安装太复杂,证书生成及其手工操作太多了,没有安装成功;helm方式的安装,v1.7.0的chart包执行安装会报错,手工修复了报错并修改了镜像地址,还是各…...

OK3568 forlinx系统编译过程及问题汇总
1. 共享文件夹无法加载;通过网上把文件夹加载后,拷贝文件很慢,任务管理器查看发现硬盘读写速率很低。解决办法:重新安装vmware tools。 2. 拷贝Linux源码到虚拟机,解压。 3. 虚拟机基本库安装 forlinxubuntu:~$ sudo…...
JVM篇---第五篇
系列文章目录 文章目录 系列文章目录一、简述Java的对象结构二、如何判断对象可以被回收?三、JVM的永久代中会发生垃圾回收么?一、简述Java的对象结构 Java对象由三个部分组成:对象头、实例数据、对齐填充。 对象头由两部分组成,第一部分存储对象自身的运行时数据:哈希码…...
C/C++ 排序算法总结
1.冒泡排序 https://blog.csdn.net/weixin_49303682/article/details/119365319 1 #include <stdio.h>2 3 #define N 94 5 void print(int a[])6 {7 for(int i 0; i < N; i)8 {9 printf("%d ", a[i]); 10 } 11 printf("…...

机器学习---RBM、KL散度、DBN
1. RBM 1.1 BM BM是由Hinton和Sejnowski提出的一种随机递归神经网络,可以看做是一种随机生成的 Hopfield网络,是能够通过学习数据的固有内在表示解决困难学习问题的最早的人工神经网络之 一,因样本分布遵循玻尔兹曼分布而命名为BM。BM由二…...
(c语言)有序序列合并
#include<stdio.h>//输入包含三行 //第一行包含两个正整数n,m,用空格分割,n表示第二行第一个升序序列中 //数字的个数,m表示第三行第二个升序序列中数字的个数 //第二行包含n个整数,用空格分割 //第三行包含m个整数,用空格分割 //输出…...

小谈设计模式(18)—适配器模式
小谈设计模式(18)—适配器模式 专栏介绍专栏地址专栏介绍 适配器模式角色分析目标接口(Target)源接口(Adaptee)适配器(Adapter) 核心思想应用场景Java程序实现输出结果程序分析123 优…...

Python柱形图
柱形图 柱形图,又称长条图、柱状统计图、条图、条状图、棒形图,是一种以长方形的长度为变量的统计图表。长条图用来比较两个或以上的价值(不同时间或者不同条件),只有一个变量,通常利用于较小的数据集分析…...

用OpenCV(Python)获取图像的SIFT特征
import cv2 as cv import numpy as np import matplotlib.pyplot as plt imgcv.imread("../Lena.png") img_graycv.cvtColor(img,cv.COLOR_BGR2GRAY)#创建一个SIFI对象 siftcv.SIFT_create()#使用SIFT对象在灰度图像img_gray中检测关键点,结果存储在变量k…...

阿里云ECS和轻量服务器有什么区别?
阿里云服务器ECS和轻量应用服务器有什么区别?轻量和ECS优缺点对比,云服务器ECS是明星级云产品,适合企业专业级的使用场景,轻量应用服务器是在ECS的基础上推出的轻量级云服务器,适合个人开发者单机应用访问量不高的网站…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...