c++操作符重载

一、运算符重载:

1、定义:

重载操作符是具有特殊函数名的函数,关键字operator后面接需要定义的 操作符符号。操作符重载也是一个函数,具有返回值和形参表。它的形参 数目与操作符的操作数目相同,使用运算符重载可以提高代码的可读性   返回值 operator 操作符(参数列表)

(1)可以重载的运算符(除了不可重载的运算符,其余的操作符都是可以重载的操作符)

(2)不可以重载的运算符

2、赋值运算符:

(1)编译器把运算符合成了,编译器可以识别两个对象,d2=d1把d1中的内容拷贝到d2,类似于拷贝构造函数,把一个对象的内容原封不动的拷贝到另一个对象。有的情况会产生问题:若是两个对象公用同一块内存空间,一个空间销毁,会使另外一个空间成为野指针。还存在内存泄漏

(2)显式的重载赋值运算符

1‘、使用类的成员函数来写,有一个隐藏的this指针,看起来只有一个参数,实际上有两个参数。不论是返回值还是参数的位置,若是给定一个类类型的对象,最好给成引用,引用的方式不用创造临时对象。赋值操作符右操作数不发生改变,所以参数最好用const修饰

class Date
{
public:
	Date(int year=290,int month=11,int day=1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int):" << this << endl;
	}
	Date(const Date &d)
		:_year(d._year)
		,_month(d._month)
		, _day(d._day)
	{
		cout << "Date(const Date &):" << this << endl;
	}
	void operator=(const Date&d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
 };
 
int main()
{
	Date d1(122, 3, 4);
	Date d2;
//Date d3(1223,4,5);
//d1=d2=d3;
	d2 = d1; //d2.operator=(d1);//Date::operator=(&d2,&d1)d1:通过参数压栈传入,d2通过ecx寄存器传入
   	return 0;
}
 

缺陷不能连续赋值:如:d1=d2=d3:d3赋值给d2,d2赋值给d1:d1.operator=(d2.operator=(d3))

方式2:返回左操作数

Date& operator=(const Date&d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;//d外部实参的引用,this是当前对象,
		//this和d的生命周期都比函数的生命周期长,但是我们返回this指针,因为
		//需要返回左操作数
	}

缺陷:不能自己给自己赋值,如:d1=d1和Date d4=&d1;……d1=d4;

方式三:判断自己给自己赋值,即this与当前的地址是否相同

Date& operator=(const Date&d)
	{
		if (this!=&d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this; 
	}

3、注意

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

(2)重载操作符必须有一个类类型或者枚举类型的操作数

构造一个加法的函数位于全局范围(普通的成员函数)内,这个加法函数有几个参数,给出几个参数,没有隐式的this指针)

1‘直接返回左操作数加右操作数不成立,需要给定一个自定义类型

class Date
{
public:
	Date(int year=290,int month=11,int day=1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int):" << this << endl;
	}
	Date(const Date &d)
		:_year(d._year)
		,_month(d._month)
		, _day(d._day)
	{
		cout << "Date(const Date &):" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
 };
int operator + (int left, int right)
{
	return left + right;
}
因为+可以直接处理整形的加号,应该给一个自定义的类型:枚举就是自定义类型
enum DATA{ ONE, TWO, THREE };
int operator + (int left, DATA right)
{
	return left + right;
}

(3)用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义

Date operator+(int days) 	{
		Date tmp(*this);
		tmp._day -= days;
		return tmp;
	}

(4)作为类成员的重载函数,其形参看起来比操作数数目少1成员函数的 操作符有一个默认的形参this,限定为第一个形参

:写成类的成员函数,若是有两个操作数,只需要给一个操作数,若是有一个操作数,就不用给了。有一个隐含的this指针。

(5)一般将算术操作符定义为非成员函数(给成普通函数,会传两个参数,更加清晰),将赋值运算符定义成员函数

(6)操作符定义为非类的成员函数时,一般将其定义为类的友元 

(7)== 和 != 操作符一般要成对重载

(8)下标操作符[]:一个非const成员并返回引用,一个是const成员并 返回引用

(9)解引用操作符*和->操作符,不显示任何参数

(10)前置式++/–必须返回被增量或者减量的引用,后缀式操作符必须返 回旧值,并且应该是值返回而不是引用返回

++只有一个参数,所以给成成员函数的时候,不需要给定参数。有返回值。返回值的生命周期比函数长,则使用引用。

class Date
{
public:
	Date(int year=290,int month=11,int day=1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int):" << this << endl;
	}
	Date(const Date &d)
		:_year(d._year)
		,_month(d._month)
		, _day(d._day)
	{
		cout << "Date(const Date &):" << this << endl;
	}
	//前置++与后置++的类型相同
	//同一个作用域里面定义两个作用域和原型都相同的函数,给另外一个函数给一个参数,构成重载
	//a=++b;
	Date& operator++()//前置++:用加完后的新值进行返回
	{
		_day += 1;
		return *this;
	}
	//a=b++;
	Date operator++(int)//后置++:用原来的旧值进行返回,后面比前置++多一个参数//不需要用引用,不能返回栈里面的值,
		//直接返回一个值
	{
		Date tmp(*this);//用一个临时变量来保存旧值
		_day += 1;//当前对象加1
		return *this;//返回加1之前的旧值
	}
private:
	int _year;
	int _month;
	int _day;
 };
int main()
{
	Date d1(122, 3, 4);
	Date d2;
	d2 = d1++;  
   	return 0;
}
后置++成员函数里面只给了一个参数,有两个参数,而实际传参的时候只传了一个参数(编译器已经替我们传递了一个参数),参数只给出了类型,没有给定值。因为后置++给一个参数是为了和前置++形成重载,所以不需要值;这里的这个参数我们不使用,但是必须给出来。

(11)输入操作符>>和输出操作符<<必须定义为类的友元函数

输出操作符不能直接输出一个对象,因为对象里面包含了多个成员,不确定是输出哪一个成员。重载输出运算符,输出运算符可以连着输出,输出运算符有两个操作数。

a、不能处理"cout<<d3;"这种输出,可以处理"d3.operator<<(cout);"和"d3<<cout;"这两种情况因为该函数(如下)有两个参数,第一个参数是当前调用对象的地址(this),所以cout不能出现在左边,cout是右操作数。

class Date
{
public:
	Date(int year = 2943, int month = 243,int day = 2)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}
	void operator<<(ostream & _cout)//ostream输出流对象
	{
		_cout << _year << "/" << _month << "/" << _day;//输出运算符的重载不用换行,外部用户自己定义
	}
private:
	int _year;
	int _month;
	int _day;
};
void TestDate()
{
	Date d1(234, 5, 6);
	Date d2(d1);
	Date d3;
	d3 = d2;
	d3.operator<<(cout);
	d3 << cout;
}

b、输出操作符的本意是“cout<<d3;”把d3写入到,再把对象输出到控制台;上面的方式"d3<<cout;"把cout当成了参数(放到了对象之中。不符合常规。改进:不把输出操作符重载成类的成员函数(全局函数),给成普通的函数(括号之中有几个参数,就有几个参数),但是此程序会产生错误,因为成员变量是私有的。

class Date
{
public:
	Date(int year = 2943, int month = 243,int day = 2)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}
private:
	int _year;
	int _month;
	int _day;
};
void operator<<(ostream &_cout, const Date&d)//此时cout作为左操作数,要打印中的内容作为右操作数
{
	_cout << d._year << "/" << d._month << "/" << d._day;
}
void TestDate()
{
	Date d1(234, 5, 6);
	Date d2(d1);
	Date d3;
	d3 = d2;
	d3.operator<<(cout);
	d3 << cout;
}

程序产生错误:类外函数访问类中私有成员,改进:

方法1:写一些公有的成员函数,将类中的私有成员获取出来,调用这些公有的接口实现

方法2:友元

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date &d);
public:
	Date(int year = 2943, int month = 243,int day = 2)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream &operator<<(ostream &_cout, const Date&d)//此时cout作为左操作数,对象中的内容作为右操作数
{
	_cout << d._year << "/" << d._month << "/" << d._day;
	return _cout;//cout的生命周期比函数长,需要返回引用
}
void TestDate()
{
	Date d1(234, 5, 6);
	Date d2(d1);
	Date d3;
	cout << d3 << endl;
}

c、不能连着输出,因为应该有返回值

ostream &operator<<(ostream &_cout, const Date&d)//此时cout作为左操作数,对象中的内容作为右操作数
{
	_cout << d._year << "/" << d._month << "/" << d._day;
	return _cout;//cout的生命周期比函数长,需要返回引用
}

实现日期函数:加、减,两个日期相减,两个日期比大小(>,<,==,!=),前置++,--,后置++,--(日期需要考虑合法性以及是否为闰年)//哪些类需要给出拷贝构造函数,赋值运算符,析构函数?类中涉及到资源的管理,申请空间……的需要给出这三个函数。

class Date
{
public:
	Date(int year = 2943, int month = 243,int day = 2)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}
	//比大小
	bool operator>(const Date& d)
	{
		if (_year > d._year ||
			_year == d._year&&_month > d._month ||
			_year == d._year&&_month == d._month&&_day > d._day)
		{
			return true;
		}
		return false;
	}
	bool operator==(const Date &d)
	{
		return _year == d._year&&
			_month == d._month&&
			_day == d._day;
	}
	bool operator!=(const Date& d)
	{
		return !(*this == d);//相等返回真,取反即为假
	}
	//a=++b;
	Date& operator++()//前置++:用加完后的新值进行返回
	{
		_day += 1;
		return *this;//this的生命周期比函数长
	}
	//a=b++;
	Date operator++(int)
	{
		Date tmp(*this);
		_day += 1;
		return *this;
	}

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

知道一个函数的运行时间(精确计算)(包括cpu的精度)

函数调用过程的理解,如下函数:

(1)返回临时变量

class Test
{
public:
	Test()
	{
		cout << "Test():" << this << endl;
	}
	Test(const Test& t)
	{
		cout << "Test(const Test& t):" << this << endl;
	}
	//赋值运算符的重载
	Test& operator=(const Test& t)
	{
		cout << this << "=" << &t << endl;
		if (this != &t)
		{
			;//赋值操作
		}
		return *this;
	}
	~Test()
	{
		cout << "~Test():" << this << endl;
	}
};
Test FunTestc(Test t)
{
	Test tt1;
	Test tmp(t);
	tt1 = tmp;
	return tt1;
}
void TestFunc()
{
	Test t1;
	Test t2;
	t2 = FunTestc(t1);
}
int main()
{
	TestFunc();
	return 0;
}


(2)返回引用

Test &FunTestc(Test &t)
{
	Test tt1;
	Test tmp(t);
	tt1 = tmp;
	return t;
}
void TestFunc()
{
	Test t1;
	Test t2;
	t2 = FunTestc(t1);
}

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuruhua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值