C++类和对象(六) 运算符重载

C++类和对象(六) 运算符重载

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

1. 加号运算符重载

作用:

实现两个自定义数据类型的相加的运算
编译器提供了一个名称: operator+

成员函数运算符重载

class Person {
public:
	int m_a;
	int m_b;

	//成员函数运算符重载
	Person operator+(Person& p)
	{
		Person tmp;
		tmp.m_a = this->m_a + p.m_a;
		tmp.m_b = this->m_b + p.m_b;
		return tmp;	
	}
};

p3 = p1 + p2 // p3 = p1.operator+(p2);

全局函数运算符重载

Person operator+(Person& p1, Person& p2)
{
	Person tmp;
	tmp.m_a = p1.m_a + p2.m_a;
	tmp.m_b = p1.m_b + p2.m_b;
	return tmp;
}

p3 = p1 + p2 // p3.operator(p1, p2)

函数也可以发生重载

Person operator+(Person &p, int n)
{
    Person tmp;
    tmp.m_a = p.m_a + n;
    tmp.m_b = m.m_b + n;
    return tmp;
}

p1 = p + 4 // p1.operator(p , 4)

2. 左移运算符重载

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

//成员函数实现不了 cout << p; (只能 p << cout  格式不对)
//ostream 对象只能有一个 所以用引用的方式返回 
ostream& operator<<(ostream &cout, Person& p)
{
	cout << "p.m_a = " << p.m_a << "\np.m_b = " << p.m_b;
	return cout;//链式编程,不返回的话,后面再接 << 会报错
}

3. 递增运算符重载

作用:
通过重载递增运算符,实现自己的整型数据

#include <iostream>
using namespace std;

class Person {
	friend ostream& operator<<(ostream& cout, Person p);
public:
	Person(int a) :m_a(a) {};
	//前置++, 返回引用是为了一直对一个数据进行操作
	Person& operator++()
	{
		m_a++;
		return *this;
	}
	//后置++, int表示占位符, 区分前置后置++
	//如果这里返回值为引用,因为tmp为局部变量,用完会释放掉,使用引用就是非法操作
	Person operator++(int)
	{
		Person tmp = *this;
		m_a++;
		return tmp;
	}

private:
	int m_a;
};


ostream& operator<<(ostream &cout, Person p)
{
	cout << p.m_a;
	return cout;
}

void func()
{
	Person p1(10);

	cout << ++p1 << endl;
	//cout << p1++ << endl;
	cout << p1 << endl;

}

int main()
{
	func();

	system("pause");
	return 0;
}

4. 赋值运算符重载

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

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

如果类中有属性指向堆区, 做赋值操作也会出现深浅拷贝问题

深浅拷贝的图示:
在这里插入图片描述
在这里插入图片描述
普通的赋值运算符的错误示范:

	Person p1(10);
	Person p2(9);
	cout << p1.m_a << endl;
	cout << p2.m_a << endl;

	p2	= p1;//编译器提供的简单的值拷贝的赋值运算符

	cout << p1.m_a << endl;
	cout << p2.m_a << endl;

在这里插入图片描述

运行显示,开始两个对象的成员的地址是不一样的
使用编译器提供的赋值运算符后,地址变为了一样
说明两个对象的成员又指到了同一个位置
再次析构的时候必然会发生错误

正确的改法:

	//赋值操作符重载
	Person& operator=(const Person& p)
	{
        //m_a = p.m_a;//编译器提供的简单的浅拷贝
        //先判断是否有属性再堆区如果有,先释放干净
        if(m_a != NULL)
        {
            delete m_a;
            m_a = NULL;
        }
        //深拷贝
		m_a = new int(*p.m_a);//重新再堆区开辟了内存空间
        return *this;//返回自身
	}

在这里插入图片描述

加引用才返回真正的自身,不然返回的是自身的拷贝
return *this 返回自身

5. 关系运算符重载

作用:
重载关系运算符,可以让两个自定义类型的对象进行对比操作

	bool operator==(Person& p)
	{
		if (m_a == p.m_a)
			return true;
		else
			return false;
	}
	bool operator!=(Person& p)
	{
		if (m_a == p.m_a)
			return false;
		else
			return true;
	}

6. 函数调用运算符重载

函数调用运算符 () 也可以重载
由于重载后的使用方式非常像函数调用,也叫仿函数(重载小括号)
仿函数没有固定的写法,非常灵活

class MyPrint {
public:
	void operator()(string str)
	{
		cout << str << endl;
	}
};

class MyAdd {
public:
	int operator()(int a, int b)
	{
		return a + b;
	}
};

void func()
{
	MyPrint mp;
	mp("hello");
	MyPrint()("world");//匿名函数对象调用

	MyAdd myadd;
	cout << myadd(3, 4) << endl;
}

MyPrint()在调用一个匿名对象,然后再调用函数
匿名对象当前行调用,当前行执行完释放
以后看到一个类型加小括号第一反应 这就是匿名对象,后面小括号就是使用它重载的运算符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值