【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;
}
运行情况:
注意:构造函数被称为默认成员函数,就是因为我们即使不写,编译器也会默认给我们生成。不过,编译器生成的默认构造函数的特点:
- 我们不写才会生成,我们写了就不会生成了。
- 内置类型的成员不会处理,【C++11声明可以给缺省值】
- 自定义类型的成员才会处理,会去调用这个成员的默认构造函数
我们不写才会生成,我们写了就不会生成了。
当我们不写构造函数时,编译器会自动生成一个构造函数来对其初始化(是随机的)。
内置类型的成员不会处理,【C++11声明可以给缺省值】
所谓内置类型,就是我们学的 int, double, char, ...,指针也属于内置类型。
自定义类型的成员才会处理,会去调用这个成员的默认构造函数
看下列自定义类型的构造函数:
即,MyQueue类中有两个Stack类,所以调用两次Stack类的构造函数:
总结:一般情况下都需要我们自己写构造函数来决定初始化方式,但当成员遍历变量都是自定义类型,可以考虑不写构造函数。
默认构造函数:不传参就可以直接被调用的
- 我们不写编译器直接生成
- 无参构造函数
- 全缺省的构造函数
这三种有且只能存在一个!!!,多个并存会存在二义性。
三:析构函数
3.1:概念定义
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
即:对申请的空间资源进行销毁。
3.2:性质
析构函数是特殊的成员函数,其特征如下:
- 析构函数名是在类名前加上字符 ~。
- 无参数无返回值类型。【无法构成重载了】
- 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载。
- 对象生命周期结束时,C++编译系统系统自动调用析构函数。
- 内置类型的成员不会处理,自定义类型会去调用这个成员的默认析构函数
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()将申请的空间资源给销毁了。
四:拷贝构造
4.1:概念
在现实生活中,可能存在一个与你一样的对象,称其为双胞胎。
那么在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。
4.2:特征
拷贝构造函数也是一个特殊的成员函数。特征如下:
- 拷贝构造函数是构造函数的一个重载形式。
- 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
- 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
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;
}
因为赋值重载函数是默认成员函数,所以当我们不写时,编译器会进行操作。但是同拷贝构造函数特性一样:
- 内置类型值拷贝(浅拷贝)
- 自定义类型调用拷贝构造,赋值重载成员函数(深拷贝,需要我们自己动手写(有空间资源申请的对象类型))
附加理解:
我们已经知道对象与对象之间可以相互比较了。那么对象和对象之间可以相互加减,对象和数字可以相互加减吗?
答:可以的
以日期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*
以下问题【权限可以缩小和平移,不可以放大】:
- const对象可以调用非const成员函数吗?答:不会,权限放大
- 非const对象可以调用const成员函数吗?答:会,权限缩小
- const成员函数内可以调用其它的非const成员函数吗?答:不会,权限放大
- 非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对象取地址的运行流程:
因为是默认函数,所以日常自动生成就可以。
总之:这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!