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

【C++类和对象篇】类和对象的六大默认成员函数——构造,析构,拷贝构造,赋值重载,普通对象取地址重载,const对象取地址重载

目录

一:六大默认成员函数

二:构造函数

2.1:前引

2.2:概念与特性

2.3:实例理解

三:析构函数

3.1:概念定义

3.2:性质

3.3:练习

四:拷贝构造

4.1:概念

4.2:特征

4.2.1:特征一

4.2.2:特征二

4.2.3:特征三

五:赋值重载

5.1:运算符重载

5.1.1:概念与特性

5.1.2:实践

5.2:赋值运算符重载

5.2.1:赋值运算符重载格式

5.2.2:实践

六:const说明

七:普通对象取地址重载和const对象取地址重载


一:六大默认成员函数

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

class Date{}

六大默认成员函数:构造函数、析构函数、拷贝构造函数、赋值重载、普通对象取地址重载、const对象取地址重载。

二:构造函数

2.1:前引

看下列代码:

#include<iostream>
using namespace std;// Date类
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;d1.Init(2024, 10, 28);d1.Print();Date d2;d2.Init(2024, 10, 29);d2.Print();return 0;
}

 对于Date类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置
信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?=>这就需要有个默认构造函数。

2.2:概念与特性

概念:构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

特征:

  • 函数名与类名相同。
  • 无返回值。
  • 对象实例化时编译器自动调用对应的构造函数。
  • 构造函数可以重载。

2.3:实例理解

 发现我们并没有调用Date()和Date(int year, int month, int day)函数,编译器直接默认调用对应的构造函数给我们初始化了。

不过为了方便通流大部分的构造函数,我们将构造函数写成全缺省的形式:

	// 上述两个构造函数可以写成 全缺省构造【通常】Date(int year = 1, int month = 1, int day = 1){cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;_year = year;_month = month;_day = day;}

看运行实例:

看一下栈的构造函数实例【加强对构造函数的理解】:

class Stack
{
public://构造函数Stack(size_t n = 4){if (n == 0){_a = nullptr;top = capacity = 0;}else{_a = (int*)malloc(sizeof(int) * n);if (_a == nullptr){perror("malloc fail");exit(-1);}top = 0;capacity = n;}}void Push(int x){// 检查扩容if (top == capacity){size_t newcapacity = capacity == 0 ? 4 : capacity * 2;int* tmp = (int*)realloc(_a, sizeof(int) * newcapacity);if (tmp == nullptr){perror("realloc fail");exit(-1);}if (tmp == _a){cout << capacity << "原地扩容" << endl;}else{cout << capacity << "异地扩容" << endl;}_a = tmp;capacity = newcapacity;}_a[top++] = x;}int Top(){assert(top > 0);return _a[top - 1];}void Pop(){assert(top > 0);top--;}bool Empty(){return top == 0;}void Destroy(){free(_a);_a = nullptr;top = capacity = 0;}private:int* _a;int top;int capacity;
};int main()
{Stack st1;		//根据构造函数默认初始化给_a数组4个int的空间for (int i = 0; i < 100; i++){st1.Push(i);}while (!st1.Empty()){cout << st1.Top() << " ";st1.Pop();}st1.Destroy();cout << endl;cout << "-----------------------------------------------------------------------------------------------" << endl;Stack st2(0);	for (int i = 0; i < 100; i++){st2.Push(i);}while (!st2.Empty()){cout << st2.Top() << " ";st2.Pop();}st2.Destroy();cout << endl;cout << "---------------------------------------------------------------------------------------------------" << endl;Stack st3(100);		// 在知道要开多少空间时,初始化时指定要开多少空间,不需要再频繁的扩容了for (int i = 0; i < 100; i++){st3.Push(i);}while (!st3.Empty()){cout << st3.Top() << " ";st3.Pop();}st3.Destroy();cout << endl;cout << "-------------------------------------------------------------------------------------------------------" << endl;return 0;
}

运行情况:

 注意:构造函数被称为默认成员函数,就是因为我们即使不写,编译器也会默认给我们生成。不过,编译器生成的默认构造函数的特点:

  1. 我们不写才会生成,我们写了就不会生成了。
  2. 内置类型的成员不会处理,【C++11声明可以给缺省值】
  3. 自定义类型的成员才会处理,会去调用这个成员的默认构造函数

我们不写才会生成,我们写了就不会生成了。

当我们不写构造函数时,编译器会自动生成一个构造函数来对其初始化(是随机的)。

内置类型的成员不会处理,【C++11声明可以给缺省值】

所谓内置类型,就是我们学的 int, double, char, ...,指针也属于内置类型

自定义类型的成员才会处理,会去调用这个成员的默认构造函数

看下列自定义类型的构造函数:

即,MyQueue类中有两个Stack类,所以调用两次Stack类的构造函数:

 总结:一般情况下都需要我们自己写构造函数来决定初始化方式,但当成员遍历变量都是自定义类型,可以考虑不写构造函数。

默认构造函数:不传参就可以直接被调用的

  1. 我们不写编译器直接生成
  2. 无参构造函数
  3. 全缺省的构造函数

这三种有且只能存在一个!!!,多个并存会存在二义性。

三:析构函数

3.1:概念定义

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

:对申请的空间资源进行销毁。

3.2:性质

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值类型。【无法构成重载了】
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
  5. 内置类型的成员不会处理,自定义类型会去调用这个成员的默认析构函数

3.3:练习

例如书写一个栈:

平常的写法:在代码的结尾还需将申请的空间给释放掉(Destroy函数)

class Stack
{
public:Stack(size_t n = 4){if (n == 0){_a = nullptr;top = capacity = 0;}else{_a = (int*)malloc(sizeof(int) * n);if (_a == nullptr){perror("malloc fail");exit(-1);}top = 0;capacity = n;}}void Push(int x){// 检查扩容// CheckCapacity();_a[top++] = x;}// 其他函数用法void Destroy(){free(_a);_a = nullptr;top = capacity = 0;}private:int* _a;int top;int capacity;
};int main()
{Stack st;st.Push(1);st.Push(2);st.Destroy();    //必须要写return 0;
}

使用析构函数:

class Stack
{
public:Stack(size_t n = 4){if (n == 0){_a = nullptr;top = capacity = 0;}else{_a = (int*)malloc(sizeof(int) * n);if (_a == nullptr){perror("malloc fail");exit(-1);}top = 0;capacity = n;}}void Push(int x){// 检查扩容// CheckCapacity();_a[top++] = x;}// 其他函数用法~Stack(){free(_a);_a = nullptr;top = capacity = 0;}private:int* _a;int top;int capacity;
};int main()
{Stack st;st.Push(1);st.Push(2);return 0;
}

对于该代码进行析构函数调试:

发现就在该程序结束的时候,我们并没有使用Destroy函数而是默认调用了析构函数~Stack()将申请的空间资源给销毁了。

即:如果类中没有申请空间资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

四:拷贝构造

4.1:概念

在现实生活中,可能存在一个与你一样的对象,称其为双胞胎。

那么在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。

4.2:特征

拷贝构造函数也是一个特殊的成员函数。特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
  3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

4.2.1:特征一

拷贝构造函数是构造函数的一个重载形式。

以Date类分析拷贝构造函数:

class Date
{
public:// 构造函数Date(int year =1,int month=1,int day=1){_year = year;_month = month;_day = day;}// 拷贝构造函数Date(Date& d1){cout << "Date(Date& d1)" << endl;_year = d1._year;_month = d1._month;_day = d1._day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year;int _month;int _day;
};

查看运行实例:

4.2.2:特征二

拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

若不使用类类型对象的引用,直接报错。 

 为什么会引发无限递归调用呢?

那么使用引用就再也不会出现这一问题:

 发现引用并没有什么的多次调用拷贝构造,因为引用并不需要创建新对象,更不需要再为新对象进行新一轮的拷贝构造。

4.2.3:特征三

若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

因为拷贝构造是默认的成员函数,那么我们不写编译器就是回默认生成。 

就是发现不写编译器是能够默认生成的。这种方式拷贝叫做浅拷贝,也叫做值拷贝(只是简单的拷贝原封不动的值过去)
编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?
当然像日期类这样的类是没必要的。那么下面的栈类呢?

class Stack
{
public://构造函数Stack(size_t n = 4){if (n == 0){_a = nullptr;top = capacity = 0;}else{_a = (int*)malloc(sizeof(int) * n);if (_a == nullptr){perror("malloc fail");exit(-1);}top = 0;capacity = n;}}void Push(int x){// 检查扩容// CheckCapacity();_a[top++] = x;}// 其他函数用法// 析构函数~Stack(){free(_a);_a = nullptr;top = capacity = 0;}private:int* _a;int top;int capacity;
};int main()
{Stack st1;st1.Push(1);st1.Push(2);Stack st2(st1);return 0;
}

发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。

分析:

 所以,因为当程序结束的时候,会调用析构函数进行空间资源释放。即当释放了st2的空间资源后,堆上的空间已经被释放了。此时_a指向的就是一个无意义的地址。再次运行st1对象的的析构函数。就会进行二次释放,导致出错。下面进行调试检测:

 所以,此刻我们就必须要写上拷贝构造【属于深拷贝】

	// 深拷贝// Stack st(s)Stack(const Stack& s){cout << "Stack(Stack& s)" << endl;//深拷贝_a = (int*)malloc(sizeof(int) * s.capacity);if (_a == nullptr){perror("malloc fail");exit(-1);}memcpy(_a, s._a, sizeof(int) * s.top);top = s.top;capacity = s.capacity;}

通过调试就发现两个对象指向了不同空间:

所以:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请
时,则拷贝构造函数是一定要写的,否则就是浅拷贝。 

总结:

 若是内置类型,编译器就会执行值拷贝(浅拷贝),若是自定义类型,就会调用它的拷贝构造。即Date类不需要我们实现拷贝构造,默认生成的就可以用。Stack类需要我们自主实现深拷贝的拷贝构造,否则就会出现问题。

五:赋值重载

5.1:运算符重载

5.1.1:概念与特性

        C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

运用形式:

  • 函数名字为:关键字operator后面接需要重载的运算符符号。
  • 函数原型:返回值类型 operator操作符(参数列表)

注意特性:

  • 不能通过连接其他符号来创建新的操作符:比如operator@ 
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  •  .*  ::  sizeof  ?:  . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

5.1.2:实践

我们知道可以使用 >,<,==,+等一系列符号来操作内置类型进行比大小,加减等操作。那么使用这些符号能不能操作自定义类型呢?

答案:不可以直接上手操作。需要定义运算符。

看操作:

例如 :小于号 <

class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// Date d(d1)Date(Date& d1){_year = d1._year;_month = d1._month;_day = d1._day;}//判断 d1 < d// d1.operator(d)// 隐含的this指的是 d1bool 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;}}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{int x = 1;int y = 2;bool ret1 = x < y;cout << ret1 << endl;Date d1(2024, 11, 1);Date d(2024, 10, 1);// bool ret2 = d1.operator<(d);bool ret2 = d1 < d;		// d1.operator<(d) <==> d1<dcout << ret2 << endl;return 0;
}

通过运算符就可以来实现对对象的比较。

即实现对象与对象之间的比较:

#include<stdbool.h>
#include<iostream>
using namespace std;class Date
{
public:// 构造Date(int year = 1, int month = 1, int day = 1);//拷贝构造Date(Date& d1);//打印函数void Print();//判断 d1 < dbool operator<(const Date& d);//判断 d1 == dbool operator==(const Date& d);//判断 d1 <= dbool operator<=(const Date& d);//判断 d1 > dbool operator>(const Date& d);//判断 d1 >= dbool operator>=(const Date& d);//判断 d1 != dbool operator!=(const Date& d);private:int _year;int _month;int _day;
};// 构造函数
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}// 拷贝构造// Date d(d1)
Date::Date(Date& d1)
{_year = d1._year;_month = d1._month;_day = d1._day;
}void Date::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}//判断 d1 < d
// d1.operator(d)
// 隐含的this指的是 d1
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 && _day < d._day){return true;}else{return false;}
}//判断 d1 == d
bool Date::operator==(const Date& d)
{return (_year == d._year)&& (_month == d._month)&& (_day == d._day);
}//判断 d1 <= d
bool Date::operator <= (const Date & d)
{return (*this < d) || (*this == d);
}//判断 d1 > d
bool Date::operator>(const Date& d)
{return !(*this <= d);
}//判断 d1 >= d
bool Date::operator>=(const Date& d)
{return !(*this < d);
}//判断 d1 != d
bool Date::operator!=(const Date& d)
{return !(*this == d);
}int main()
{Date d1(2024, 11, 1);Date d(2024, 10, 1);bool ret1 = d1 < d;bool ret2 = d1 == d;bool ret3 = d1 <= d;bool ret4 = d1 > d;bool ret5 = d1 >=d;bool ret6 = d1 != d;cout << ret1 << endl;cout << ret2 << endl;cout << ret3 << endl;cout << ret4 << endl;cout << ret5 << endl;cout << ret6 << endl;return 0;
}运行结果:
0
0
0
1
1
1

5.2:赋值运算符重载

5.2.1:赋值运算符重载格式

  • 参数类型:const Date&,传递引用可以提高传参效率
  • 返回值类型:Date&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测是否自己给自己赋值
  • 返回*this :要符合连续赋值的含义

5.2.2:实践

//赋值拷贝
Date& operator=(const Date& d)
{if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}int main()
{Date d1(2024, 11, 1);Date d2(d1);	// 拷贝构造,一个已存在的对象去初始化另一个要创建的对象Date d3;d3 = d1;		//赋值拷贝,两个已存在的对象进行拷贝return 0;
}

因为赋值重载函数是默认成员函数,所以当我们不写时,编译器会进行操作。但是同拷贝构造函数特性一样:

  1. 内置类型值拷贝(浅拷贝)
  2. 自定义类型调用拷贝构造,赋值重载成员函数(深拷贝,需要我们自己动手写(有空间资源申请的对象类型))

附加理解:

我们已经知道对象与对象之间可以相互比较了。那么对象和对象之间可以相互加减,对象和数字可以相互加减吗?

答:可以的

以日期Date类为例:

#include<stdbool.h>
#include<iostream>
using namespace std;class Date
{
public:// 构造Date(int year = 1, int month = 1, int day = 1);//拷贝构造// Date(Date& d1);//赋值拷贝Date& operator=(const Date& d);//打印函数void Print();//判断 d1 < dbool operator<(const Date& d);//判断 d1 == dbool operator==(const Date& d);//判断 d1 <= dbool operator<=(const Date& d);//判断 d1 > dbool operator>(const Date& d);//判断 d1 >= dbool operator>=(const Date& d);//判断 d1 != dbool operator!=(const Date& d);// Date类型 +/- int型Date& operator+=(int day);Date operator+(int day);Date& operator-=(int day);Date operator-(int day);// Date型前置/后置 ++/--// 前置++,++dDate& operator++();// 后置++,d++// 加一个int参数,进行占位,跟前置++构成函数重载进行区分Date operator++(int);// 前置--,--dDate& operator--();// 后置--,d--Date operator--(int);// Date类 - Date类int operator-(const Date& d);private:int _year;int _month;int _day;
};#define _CRT_SECURE_NO_WARNINGS#include"Func.h"// 构造函数
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}// 拷贝构造
//  Date d(d1)
//Date::Date(Date& d1)
//{
//	_year = d1._year;
//	_month = d1._month;
//	_day = d1._day;
//}//赋值拷贝
Date& Date::operator=(const Date& d)
{if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}void Date::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}//判断 d1 < d
// d1.operator(d)
// 隐含的this指的是 d1
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 && _day < d._day){return true;}else{return false;}
}//判断 d1 == d
bool Date::operator==(const Date& d)
{return (_year == d._year)&& (_month == d._month)&& (_day == d._day);
}//判断 d1 <= d
bool Date::operator <= (const Date & d)
{return (*this < d) || (*this == d);
}//判断 d1 > d
bool Date::operator>(const Date& d)
{return !(*this <= d);
}//判断 d1 >= d
bool Date::operator>=(const Date& d)
{return !(*this < d);
}//判断 d1 != d
bool Date::operator!=(const Date& d)
{return !(*this == d);
}// 获取日期类某年某个月天数
int GetMonthDay(int year, int month)
{static int MonthDay[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 MonthDay[month];
}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;}}
}Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}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;
}Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}// Date型前置/后置 ++/--
// 前置++,++d
Date& Date::operator++()
{(*this) += 1;return *this;
}// 后置++,d++
Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}// 前置--,--d
Date& Date::operator--()
{(*this) -= 1;return *this;
}// 后置--,d--
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}// Date类 - Date类
int Date::operator-(const Date& d)
{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;
}

六: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;
};int main()
{Date d1(2024, 11, 1);d1.Print();const Date d2(2022, 6, 7);d2.Print();return 0;
}// 运行结果:
Print()
year:2024
month:11
day:1Print()const
year:2022
month:6
day:7

所以,Print函数构成了函数重载。why?

答:一个Print函数内参数类型是Date*,另一个Print函数内参数类型是const Date*

以下问题【权限可以缩小和平移,不可以放大】:

  1. const对象可以调用非const成员函数吗?答:不会,权限放大
  2. 非const对象可以调用const成员函数吗?答:会,权限缩小
  3. const成员函数内可以调用其它的非const成员函数吗?答:不会,权限放大
  4. 非const成员函数内可以调用其它的const成员函数吗?答:会,权限缩小

不过这两个Print是没有意义的。看以下有意义的代码:

class SeqList
{
public:void PushBack(int x){// 检查容量_a[size++] = x;}int& operator[](int i){assert(i < size);return _a[i];}const int& operator[](int i) const{assert(i < size);return _a[i];}size_t Size() const{return size;}~SeqList(){free(_a);_a = nullptr;size = capacity = 0;}
private:int* _a = (int*)malloc(sizeof(int) * 10);int size;int capacity;
};void Print1(SeqList& sl)
{cout << "void Print1(SeqList& sl)" << endl;for (int i = 0; i < sl.Size(); i++){cout << sl[i] << " ";}cout << endl;
}
void Print1(const SeqList& sl)
{cout << "void Print1(const SeqList& sl)" << endl;for (int i = 0; i < sl.Size(); i++){cout << sl[i] << " ";}cout << endl;
}int main()
{SeqList s;s.PushBack(1);s.PushBack(2);s.PushBack(3);s.PushBack(4);for (int i = 0; i < s.Size(); i++){cout << s[i] << " ";}cout << endl;for (int i = 0; i < s.Size(); i++){s[i] *= 2;}cout << endl;for (int i = 0; i < s.Size(); i++){cout << s[i] << " ";}cout << endl;Print1(s);return 0;
}

调用了两个operator[],进行函数重载。

  • 读:const int& operator[](int i) const
  • 读和写: int& operator[](int i)

此刻const的意义就显得重要了。

七:普通对象取地址重载和const对象取地址重载

普通对象取地址和const对象取地址是有一些区别联系的。

普通对象取地址:

	Date* operator&(){return this;}

const对象取地址:

	const Date* operator&() const{return this;}

通过调试来确定普通对象和const对象取地址的运行流程:

因为是默认函数,所以日常自动生成就可以。

总之:这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!


http://www.mrgr.cn/news/65422.html

相关文章:

  • 【Linux探索学习】第十弹——Linux工具篇(五):详解Linux 中 Git 工具的使用与相关知识点
  • SVN 提交操作
  • 《欢乐饭米粒儿9》第五期:用笑声诠释生活,让爱成为日常
  • 针对告警数量、告警位置、告警类型等参数进行统计,并做可视化处理的智慧能源开源了。
  • uniapp
  • 华为鲲鹏一体机 安装笔记
  • Aurora 64b/66bIP核学习
  • 开发者的黄金时代:原生鸿蒙应用市场的全生命周期服务
  • 2024版红娘金媒10.3婚恋相亲系统源码小程序(亲测)
  • transformers 框架使用详解,bert-base-chinese
  • 第4章 Linux必备命令
  • QT 如何使QLabel的文字垂直显示
  • 微服务系列一:基础拆分实践
  • 什么是pipeline?
  • favicon是什么文件?如何制作网站ico图标?
  • 《安全软件开发框架(SSDF) 1.1:降低软件漏洞风险的建议》解读(四)
  • Fish Agent:多语言 Voice-to-Voice 开源语音模型;Runway 推出摄像机运镜功能丨 RTE 开发者日报
  • NVR管理平台EasyNVR多个NVR同时管理:高效管理分散视频资源的全能解决方案
  • 2024年下半软考准考证打印通知及打印说明!
  • 星河计划——北京同仁堂科技发展集团第三终端学术交流研讨会成功举办
  • 一个git相关的cve:CVE-2024-32002
  • 使用 asyncio.run_coroutine_threadsafe 在 Python 中处理异步操作
  • 如何更改Android studio的项目存储路径
  • 北斗有源终端|智能5G单北斗终端|单兵|单北斗|手持机
  • 智算中心建设热潮涌动 AI服务器赋能加速
  • pytorch初学者理解网络的神器summary