类和对象(4)--《Hello C++ Wrold!》(6)--(C/C++)--赋值运算符重载,取地址和const取地址操作符重载

前言

这期的话会讲解剩余的三个默认成员函数–赋值运算符重载,取地址和const取地址操作符重载

类的剩下三个默认成员函数

赋值运算符重载

运算符重载

作用:让eg:+在自定义类型中也能使用

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)

eg: bool operator +(const Data& a)
延申: bool ret = 1<2;这样也是可以的:ret会 = true;
     operator左右操作数的取哪个跟左右结合性无关哈

1.不能通过连接其他符号来创建新的操作符:比如operator@

2.重载操作符必须有一个类类型参数或者枚举类型(成员函数的话,this也算类类型参数)

3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义

作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

.*          ::        sizeof       ?:          .
(这个易忘)

注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

运算符重载是可以显示调用的

Date& operator=(const Date& d)//d1传给的是this指针,this == &d1
{
_year = d._year;
_month = d._month;
_day = d._day;
}
main函数里面 d1 = d2
//等效为d1.operator=(d2),像这种两个操作数的都是这样看的,前面那个在operator前面……
//operator=(&d1, d2)

要注意的是运算符重载和拷贝构造函数区分

d2 = d1;//属于已经存在的两个对象之间的复制拷贝的话--运算符重载函数
//不是d1(d2)
Date d2(d1)//用一个已经存在的对象初始化另一个对象--拷贝构造函数
//等价于 Date d2 = d1;

赋值运算符重载

重载时一般要做到这几点才不会错:

参数类型:const 类型&

返回值类型:类型&–不能void,不然连续赋值就遭了

返回*this

注意把自己给自己赋值那个判断一下,提高效率

注意:赋值运算符一定要重载成成员函数,不然系统还会自己再生成一个

Date& operator=(const Date& d)
 {
 if(this != &d)//这个操作还行
       {
            _year = d._year;
            _month = d._month;
            _day = d._day;
       }
        
        return *this;
 }

系统自动生成的赋值重载函数:(跟拷贝构造的这个规则差不多)

1.内置类型成员进行浅拷贝

2.自定义类型成员会去调用他的赋值重载

基本流运算符重载

printf处理不了自定义类型的东西,但是基本流运算符的使用者cin,cout可以

cin(类型是:istream)和cout(类型是:ostream)支持自动识别类型的原因:

1.内置类型是因为库里面实现了

2.支持自定义类型是因为自己写的函数重载

(这个的函数重载的例子也在下面的日期类实现那里)

注意:基本运算符不能写成成员函数

可以显示调用:

cout<<d1;--operator<<(cout,d1);

基本流运算符不能写成成员函数的原因:

要写成成员函数的话,对象要占用operator的左操作数才行(因为this指针会去悄咪咪的占了),写出来就会是下面这个样子,不符合使用习惯

void operator<<(ostream& out);

取地址及const取地址操作符重载

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

关于const的引申

1.也是有权限缩小,平移,扩大的那个问题

const int a = 10;
int*pb = &a;//这个就算权限扩大了,是不行的

2.成员函数后面加const之后,普通的对象和const过了的对象都可以调用

成员函数加const:
void Print()const这样加const才表示让this指针指向的对象不能被修改

总结对第二点:

只要成员函数内部不修改成员变量,都应该加const,这样const对象和普通对象都可以调用

const对象:比如:const d1(2025,5,7);
在调用时:d2.Print();相当于d2.Print(&d2);this指向d2,所以有了上面那个说法

作业部分

设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?(B)
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
构造顺序是按照语句的顺序进行构造,析构是按照构造的相反顺序进行析构
然后因为有static,所以d的生存周期变了,但是没C长

在这里插入图片描述

下列关于赋值运算符“=”重载的叙述中,正确的是(A)
A.赋值运算符只能作为类的成员函数重载//理解
B.默认的赋值运算符实现了“深层复制”功能
C.重载的赋值运算符函数有两个本类对象作为形参//这里的形参指的是()里面的
D.如果己经定义了复制拷贝构造函数,就不能重载赋值运算符

在这里插入图片描述

&作取地址和引用的区分:
在描述类型时的&才是引用
日期类的部分实现
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{
	static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30,
                              31, 31, 30, 31, 30, 31 };//避免了每次都需要创建
	//if (((year % 4 == 0 && year % 100 != 0) ||
    //       (year % 400 == 0)) && month == 2)
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) ||
        (year % 400 == 0)))//这样更好
	{
		return 29;
	}
	else
	{
		return daysArr[month];
	}
}

  // 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);
  // 拷贝构造函数
// d2(d1)
Date(const Date& d);

  // 赋值运算符重载
Date& operator=(const Date& d);

  // 析构函数
~Date();


Date& Date::operator+=(int day)
{
 if(day<0)   return *this-=-day;//防止day是负数;这个-=要自己实现!
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)//这里不是用的while
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}

Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp += day;//就像这样,用到之前已经实现了的部分来简化
	return tmp;

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

	return tmp;
}
  // 日期-日期 返回天数
int operator-(const Date& d) const
{
	Date max = *this;
	Date min = d;
	int flag = 1;

	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;//表明那个d才是大的
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;//flag的巧用,比if来搞好
}

int GetYear()
{
  return _year;//这种方法能让私有的能拿出去
}

private:
int _year;
int _month;
int _day;
};

ostream& operator<<(ostream& out, const Date& d)
//不能改成 const ostream& out
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
//这里不能这样搞,除非设置成友元(像上面写的那样)
//对象的成员函数不是只能用成员变量用
	return out;
}

istream& operator>>(istream& in, Date& d)//注意这两个的类型!
{
	int year, month, day;
	in >> year >> month >> day;//感觉还是上面那种读法好些

	if (month > 0 && month < 13
		&& day > 0 && day <= d.GetMonthDay(year, month))
	{
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
		cout << "非法日期" << endl;
		assert(false);//这后面的操作是防止用户输入错误日期
	}

注意:前置不用加int,后置要加int这个是规定,不能颠倒,参数也不能换成其他类型,让这两个构成重载

在上面的基础上,用eg:d1++;那么编译器就会调用d1.operator(0)//调用时这的int是0

注意:前置返回++之前的对象,后置返回++之后的对象(用来实现前后置效果)

注意:对于内置类型来说,前置和后置的代价差不多,可以忽略不计;但是对自定义类型来说,前置比后置代价小不少(后置需要多构造一个临时对象),平时应该多用前置的

评论 45
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值