C++:类与对象——详解各种运算符重载

1. 运算符重载

掌握运算符最重要的是了解每个运算符重载时它的返回值类型参数类型以及是否需要参数需要几个参数

概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

注意

  1. 对于内置的数据类型,编译器知道如何进行运算

  2. 对于内置的数据类型的表达式的运算符是不可能改变的

  3. 不要滥用运算符重载

加法运算符、减法运算符较简单,此处并不列出!

2. 左移运算符重载

作用:可以输出自定义数据类型

注意:只能利用全局函数重载左移运算符(不会利用成员函数重载左移运算符,因为无法实现cout在左侧)

示例

template<class T>
ostream& operator<<(ostream& cout,T& t){
    //代码段
    return cout;
}

值得注意的是左移运算符的重载是要使用全局函数的,因为要使用到输出流ostream,而且该函数需要有返回值且返回值类型也为输出流ostream,这样才能实现链式编程

也可以将该函数作为友元来方便访问类中私有属性。

重载左移运算符配合友元可以实现输出自定义数据类型。

3. 递增运算符重载

递增运算符分为前置递增和后置递增

  • 前置递增++i,输出时先自增,后输出值

  • 后置递增i++,输出时先输出值,后自增

注意:在递增前可以选择先重载左移运算符方便输出

  • 前置递增重载时,MyInteger& operator++(),函数的返回值为自己定义的类类型的引用,原因是:前置递增在自增后,返回*this,如果返回值类型不是引用,那么在链式编程中得到的并不是原来的对象,而是其它对象。且该函数不需要参数。
  • 后置递增重载时,MyInteger operator++(int) ,函数的返回值为值类型,并不是引用,这是因为在函数体中,我们首先定义了一个临时变量记录*this,而自增后我们返回的是这个临时变量,因为后置递增是先输出值,后自增,即返回的是自增前的*this。如果返回的是引用,得到的是临时变量,导致错误。其中参数中int占位参数,可以用于区分前置和后置递增。
  • 注意以下代码中,左移运算符重载函数中第二个参数类型为值类型,这是为了适应两种自增。
#include<iostream>
#include<string>
using namespace std;
class MyInteger {
	friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
	MyInteger();

	//重载前置递增
	MyInteger& operator++() {   //注意这里返回的是引用
		this->myInt++;
		return *this;
	}

	//重载后置递增  
	MyInteger operator++(int) {  //int代表占位参数,可以用于区分前置和后置递增,注意这里返回的是值
		MyInteger temp = *this;
		this->myInt++;
		return temp;
	}
private:
	int myInt;
};
MyInteger::MyInteger() {
	this->myInt = 0;
}
ostream& operator<<(ostream& cout, MyInteger myint) {
	cout << "myint:" << myint.myInt << endl;
	return cout;
}
int main()
{
	MyInteger myint;
	cout << ++myint << endl;
	cout << myint++ << endl;
}

综上:推荐编程中多使用前置递增

4. 赋值运算符重载

c++编译器至少给一个类添加4个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  4. 赋值运算符operator=,对属性进行值拷贝

参考深拷贝与浅拷贝的内容,赋值运算也会出现堆区内存重复释放导致程序崩溃,解决方法是重新申请一块堆上的空间

注意:以下代码中,在进行赋值运算符重载时,重载函数的返回值是类类型的引用,是为了实现链式编程,举个例子就是:a = b = c。在函数体内部,先判断成员变量是否为空指针,如果非空,则进行delete操作,再重新开辟堆空间并赋值,最后返回对象本身。

class Person {
public:
	Person(int a) {
		this->m_A = new int(a);
	}
	Person& operator=(Person& p) {
		if (this->m_A != NULL) {
			delete this->m_A;
			this->m_A = NULL;
		}
		this->m_A = new int(*p.m_A);
		return *this;
	}
	int* m_A;
};

5. 关系运算符重载

作用:可以让两个自定义类型对象进行对比操作(==、<、>、<=、>=、!=…)

6. 函数调用运算符重载

  • 函数调用运算符()也可以重载
  • 由于重载后使用的方式非常像函数的调用,因此称为仿函数
  • 仿函数没有固定写法,非常灵活
class myPrint {
public:
	myPrint(string text) {
		this->text = text;
	}
	void operator()(string str) {
		cout << str << endl;
	}
	string text;
};

匿名函数对象

在下面代码中,MyAdd()(100, 100)会创建一个匿名函数对象,当前行代码执行完毕即释放该对象

示例:

class MyAdd {
public:
	int operator()(int num1, int num2) {
		return num1 + num2;
	}
};
int main()
{
	MyAdd myadd;
	int ret = myadd(10,10);
	cout << "ret = " << ret << endl;
	cout << MyAdd()(100, 100) << endl;  //匿名函数对象,当前行执行完立即释放对象
}
  • 24
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值