C++day9 运算符重载(成员,全局,函数重载),左移运算符重载,递增递减

1.加号运算符重载

作用:实现两个自定义数据类型相加的运算

如果自己自定义一个加号,很麻烦

代码(this在哪个成员函数中,则下面调用这个函数时this->m_a指的是这个函数所属类的那个成员属性。比如下面代码中的this->m_a,在test()函数调用personadd()时,值得是person类中m_b的值

class person
{
public:
	int m_a;
	int m_b = 20;
	

	person personplus(person &p)
	{
		person temp;
		temp.m_a = this->m_a + p.m_a;//这里的this->m_b必须在public中赋值才能用,不然乱码
		return temp;       //临时对象,存信息
	}
};


//全局函数重载,不能用this了
person personadd(person &p1, person &p2)
	{
		person temp;
		temp.m_a = p1.m_a + p2.m_b;
		temp.m_b = p1.m_b + p2.m_b;   
		cout << temp.m_a << endl;
		cout << temp.m_b << endl;
		return temp;
	}

void test()
{
	person p1;
	p1.m_a = 10;
	person p2;
	p2.m_a = 33;
	p2.m_b = 20;
	person p3;
	p3.personadd(p1,p2);
	person p4 = p1.personplus(p2);   //temp存着这个对象所有的信息,再赋给p4,等于p4 = p1 +p2,加号重载
	cout << "新   "<< p4.m_a << endl;
}

int main()   
{
	test();
	system("pause");              
	return 0;   
}

而编译器提供的函数名字operator+,可以将person p3 = p1.personplus(p2)简化为p3 = p1+p2,

  • 成员函数重载,本质是person p3 = p2.operator+(p1),p1.p2的先后顺序是有很大影响
  • 全局函数重载也是一样,本质上是p3 = operator+(p1,p2),p1.p2的先后顺序是有很大影响
  • 运算符重载也可以函数重载,实现如person + int 这种操作
class person
{
public:
	int m_a;
	int m_b ;
	//成员函数重载
	//person operator+(person &p)   //可以写成p,但用引用的方法节省内存空间
	//{
	//	person temp;
	//	temp.m_a = this->m_a + p.m_a;
	//	temp.m_b = this->m_b + this->m_b + p.m_b;
	//	return temp;   //注意返回一个对象,这个对象包含各属性的值
	//}
};

//全局函数重载
person operator+(person &p1,person &p2)
{
	person temp;
	temp.m_a = p1.m_a + p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}

//函数重载版本
person operator+(person &p1, int num)  //此处不能&num,因为没有别名,就是原始名
{
	person temp;
	temp.m_a = p1.m_a + p1.m_a + num;
	temp.m_b = p1.m_b + num;
	return temp;
}

void test()
{
	person p1;
	p1.m_a = 10;
	p1.m_b = 23;
	person p2;
	p2.m_a = 33;
	p2.m_b = 20;
	person p3; person p4;
	//成员函数重载p3结果
	p3 = p2 + p1;    //注意:成员函数重载,这里简化的是person p3 = p2.operator+(p1),p1.p2的先后顺序是有很大影响的。
					//	p1+p2 = 66,p2 + p1 =63
	//全局函数重载p4结果
	p4 = p2 + p1;      //全局函数重载也是一样,本质上是p3 = operator+(p1,p2) 
						//因为这里设置的是p1.m_a + p1.m_a + p2.m_a,设计的全局重载函数先后位置顺序有影响。
	//运算符重载也可以函数重载
	person p5 = p1 + 10;  //person + int,需要自己写一个重载函数
	cout << p3.m_b << endl;
	cout << p4.m_a << endl;
	cout << p5.m_a << endl;
}

int main()   
{
	test();
	system("pause");              
	return 0;   
}

注意:运算符重载不能改变元尤类型的运算,如把1+1 =2,变成1 +1 = 0

2.左移运算符重载

想输出自定义类型变量,必须左移运算符重载

如cout << p << endl;

注意:成员函数无法实现左移运算符重载,因为要使用成员函数必须用对象p来调用,则此时p已经在左边。会形成 p << cout 这种形式。(cout是一个ostream类的对象,它有一个成员运算符函数operator<<,每次调用的时候就会向 输出设备(一般就是屏幕)输出)

如void operator<<(cout) 在调用时为p.operator<<(cout) ,可简化为p << cout,简化规则为去掉.operator和(),此时变成了p << cout,反了

具体实现(注意注释)

  • 左移重载函数参数和返回值的类型最好一致,所以代码中都为ostream &,都为一个地址
  • 左移重载函数只有在符合形参条件下才会生效。以代码为例,只有cout << person类型时,才调用左移重载函数。在其他情况下,比如调用完重载函数,返回一个cout,右边为<< "你好"这种情况,<<依然为普通的<<,不会调用重载函数
class person
{
friend	ostream & operator<<(ostream &out, person &p);  //因为有些类把属性设为私有

person()
{

}
public:            //构造函数要说明公共还是私有
person(int a,int b)
{
	m_a = a;
	m_b = b;
}
private:
	int m_a;
	int m_b ;
	/*void operator<<(ostream &cout)  //成员函数,调用时相当于把p.operator<<(cout) 简化成了p << cout,p在左边,不符合
	{}*/
};

//所以左移运算符重载不能用成员函数
ostream & operator<<(ostream &out,person &p) //这里相当于p.operator<<(cout,p),简化为cout << p.
						//cout是ostream 类的一个对象,且全局只能有一个,所以加&,用引用符号,起别名,所以叫out也行
{
	out << "m_a = " << p.m_a << "  m_b = " << p.m_b << endl;
	return cout;     //这里ostream后加&,是为了使cout这个对象 地址保持不变,返回一个地址,而不是新建一个新地址的cout
}				//也可以这样理解,返回值和参数类型必须统一,参数为引用,则返回值也为引用,可能理解不深,以后再改

void test()
{
	person p1(10,23);
	//如果上面的左移重载函数返回值为空(void)
	//cout << p1 ;   //则这里<<右边必须都是person类型,不能写endl,会报错
	//如果如果上面的左移重载函数返回值为cout
	cout << "hello " << p1  << endl;
	//则可以继续用链式思想,返回一个cout,变成cout << endl;
	//这里没有调用左移重载函数,因为只有一个cout, << 右边是endl,不符合左移重载函数的形参要求,所以<<是普通的那个<<,右边可以加endl换行
	//中间也可以加个hello
}

int main()   
{
	test();
	system("pause");              
	return 0;   
}

3.递增递减重置运算符

重点:

  • /重载前置++运算符要加&,不加&返回的只是一个值,地址会随着操作不断改变。而加&后,返回的是一个固定地址的,随着操作不断改变的值。地址不变
  • 重载后置运算符不加&,返回的只是一个值。因为临时存量temp在执行后就会被释放掉,不需要固定地址(我的理解,不知道对不对,以后再修改)。
  • 此时的左移重载运算符自定义变量形参处,或是不加&,或者是const+&。因为后置运算返回的是一个值,每回的值相同,但地址都可能不同,所以不加&或其他来满足前置后置共同要求,不再要求固定地址。或者用const+&后,地址不变,也可以满足
//自定义整型
class myinteger    
{
	friend ostream & operator<<(ostream &cout, myinteger const &m);
public:
	myinteger()
	{
		m_num = 0;
	}

	//重载前置++运算符
	myinteger& operator++()  //因为只是对参数递增,且为成员函数,所以不需要传参
							//这里必须加&,不加&返回的只是一个值,再对m1进行操作时,每次的地址都不同
	{						//就是拷贝调用原则
		++m_num;
		return *this;      //this代表自身地址,*为解引用,这里返回一个自定义整型的固定地址的解引用值
	}
	//重载后置++运算符
	//int代表一个占位参数,用于区分前后置。只能写int.编译器会自动认定为后置++
	myinteger operator++(int)      //后值递增必须返回一个值,不能返回引用
	{
		//先记录当时结果
		myinteger temp = *this;
		//再递增并返回当时结果
		m_num++;
		return temp;    //这里返回值返回的地址就是
	}
private:
	int m_num;
};

ostream & operator<<(ostream &cout, myinteger const &m)//因为后置运算返回的是一个值,每回的值相同,但地址都可能不同
                                       //所以这里的myinteger m不能加&。以此满足前置后置共同的需求
										//也可以const 再加&,静态化
{
	cout << "数字  " << m.m_num << endl;
	return cout;
}


void test()
{
	myinteger m1;
	//前置
	cout << "hello " << ++(++m1) << endl;
	cout << m1 << endl;   //前置重载函数不加&时,m1为1,因为再次递增时已经是另外一个地址的m1递增。
	//后置
	cout <<  m1++ << endl;    //这两个地址不同
	cout << m1 << endl;  
}

int main()   
{
	test();
	system("pause");              
	return 0;   
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值