c++之运算符重载

目录

运算符重载的定义

运算符重载的技术推演

运算符重载的两种方法

重载运算符的写法

重载=号运算符

自己实现一个数组类


运算符重载的定义

  所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。

  运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。例如,大 家都已习惯于用加法运算符”+”对整数、单精度数和双精度数进行加法运算,如5+8, 5.8 +3.67等,其实计算机对整数、单精度数和双精度数的加法操作过程是很不相同的, 但由于C++已经对运算符”+”进行了重载,所以就能适用于int, float, double类型的运算。

运算符重载的技术推演

	int a = 0, b = 0;
	int c;
	c = a + b; //基础数据类型 编译器已经知道了如何运算

我们都知道基础类型可以直接进行运算操作,而像如果是自己定义的类型想要进行运算符运算编译器就会直接报错。

这是因为编译器不知道怎么进行运算导致错误 。所以c++编译器提供了一种机制即运算符重载来让我们自己编写如何进行运算。

在c++中使用operator来声明运算符重载的操作。

	Complex operator+(Complex c2)
	{
		Complex tmp(this->a + c2.a, this->b + c2.b);
		return tmp;
	}

例如重载+法运算符操作的话就可以使用operator+来说明。

运算符重载的两种方法

运算符重载有两种方法:一种是使用成员函数法,一种是使用全局变量法。

 

//通过类成员函数完成-操作符重载

//函数声明 Complex operator-(Complex &c2)

//函数调用分析

//用类成员函数实现-运算符重载

Complex c4 = c1 - c2;

c4.printCom();

//c1.operator-(c2);

//通过全局函数方法完成+操作符重载

//函数声明 Complex operator+(Complex &c1, Complex &c2) 

//函数调用分析

int main()

{

Complex c1(1, 2), c2(3, 4);

//Complex c31 = operator+(c1, c2);

Complex c3 = c1 + c2; 

c3.printCom();

}

 

#include <iostream>
using namespace std;

class Complex1
{
private:
	int a;
	int b;
	friend Complex1 operator+(Complex1& c1, Complex1& c2);
	
	//重载前置++
	friend Complex1& operator++(Complex1& c1);

	friend Complex1 operator++(Complex1& c1, int);
public:
	Complex1(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	void printCom()
	{
		cout << a << "+" << b << "i" << endl;
	}

	Complex1 operator-(Complex1 c2)
	{
		Complex1 tmp(this->a - c2.a, this->b - c2.b);
		return tmp;
	}

};

Complex1 operator+(Complex1 &c1, Complex1 &c2)
{
	Complex1 tmp(c1.a + c2.a, c1.b + c2.b);
	return tmp;
}

int main()
{
	Complex1 c1(1, 2), c2(3, 4);

	Complex1 c3 = c1 + c2;
	//1 全局函数法实现+运算符重载
	Complex1 c4 = c1 - c2;
	c4.printCom();


	std::cout << "Hello World!" << endl;
	return 0;
}

这个例子中展示的是重载运算符+法和-法,+法使用的是全局函数法,全局函数法需要传递符号的所有操作数作为参数,+法需要两个操作数,这边需要注意的是由于调用了Complex1类的私有变量,所以将+法函数说明为Complex1类的友元函数。

-法使用的是成员函数法,成员函数法将左操作数作为this指针指向的对象,所以只需要传递右操作数作为参数即可。

重载运算符的写法

接下来展示一下所有运算符的重载写法

#include <iostream>
using namespace std;

class Complex2
{
private:
	int a;
	int b;

	friend ostream& operator<<(ostream& out, Complex2& c1);
public:
	Complex2(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	void printCom()
	{
		cout << a << "+" << b << "i" << endl;
	}

	Complex2 operator-(Complex2 c2)
	{
		Complex2 tmp(this->a - c2.a, this->b - c2.b);
		return tmp;
	}

	//前置--
	Complex2& operator--()
	{
		this->a--;
		this->b--;
		return *this;
	}

	//后置--
	Complex2& operator--(int)
	{
		Complex2 tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}

	Complex2 operator+(Complex2& c2)
	{
		Complex2 tmp(this->a + c2.a, this->b + c2.b);
		return tmp;
	}

	//前置++
	Complex2& operator++()
	{
		this->a++;
		this->b++;
		return *this;
	}

	//后置++
	Complex2 operator++(int)
	{
		//先使用 再让c1加加
		Complex2 tmp = *this;
		this->a++;
		this->b++;
		return tmp;
	}

};

ostream& operator<<(ostream& out, Complex2& c1)
{
	cout << c1.a << "+" << c1.b << "i" << endl;
	return out;
}

int main()
{
	Complex2 c1(1, 2), c2(3, 4);

	Complex2 c3 = c1 + c2;
	//1 全局函数法实现+运算符重载
	Complex2 c4 = c1 - c2;
	c4.printCom();


	//前置++操作符 用全局函数实现
	++c1;
	c1.printCom();

	//前置--操作符
	--c1;
	c1.printCom();

	//后置++操作符 用全局函数实现
	c1++;

	//后置--操作符 用成员函数实现
	c1--;
	c1.printCom();

	std::cout << "Hello World!" << endl;
	return 0;
}

这边需要注意的是:

1、前置++和后置++由于都是一个操作数,所以在进行重载的时候无法通过参数来区分区别,(重载的定义是参数个数、参数类型不同),所以c++编译器规定在重载后置++的时候加一个int类型的占位符参数。

2、重载运算符<<是不可以用成员运算符进行重载的,由于左操作数是ostream类型,这个类型是系统的类无法进行修改,所以只能使用全局函数的方法进行重载。

重载=号运算符

我们都知道c++编译器默认是有重载=号操作符的,但是c++编译器提供的是浅拷贝操作的=号操作符重载,所以如果类中含有指针变量的时候在析构的时候会出现指针错误的情况。所以=运算符重载的时候需要我们自己实现一个,思路就是为指针变量重新开辟一块空间,再将需要复制的内容拷贝到该空间中,这样就不会出现析构两次的情况。


#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>
using namespace std;

class  Name
{
public:
	Name(const char* myp)
	{
		m_len = strlen(myp);
		m_p = (char*)malloc(m_len + 1); //
		strcpy(m_p, myp);
	}

	//Name obj2 = obj1;
	//解决方案: 手工的编写拷贝构造函数 使用深copy
	Name(const Name& obj1)
	{
		m_len = obj1.m_len;
		m_p = (char*)malloc(m_len + 1);
		strcpy(m_p, obj1.m_p);
	}

	~Name()
	{
		if (m_p != NULL)
		{
			free(m_p);
			m_p = NULL;
			m_len = 0;
		}
	}

	Name& operator=(Name& obj1)
	{
		//1先释放旧的内存
		if (this->m_p != NULL)
		{
			delete[] m_p;
			m_len = 0;
		}
		//2 根据obj1分配内存大小
		this->m_len = obj1.m_len;
		this->m_p = new char[m_len + 1];

		//把obj1赋值
		strcpy(this->m_p, obj1.m_p);

		return *this;
	}
protected:
private:
	char* m_p;
	int m_len;
};

//对象析构的时候 出现coredump
void objplaymain()
{
	Name obj1("abcdefg");
	Name obj2 = obj1;  //C++编译器提供的 默认的copy构造函数  浅拷贝
	Name obj3("obj3");

	obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝

	obj1 = obj2 = obj3;
}

void main()
{
	objplaymain();
	cout << "hello..." << endl;
	system("pause");
	return;
}

自己实现一个数组类

myarray.h

#pragma  once

#include <iostream>
using namespace std;

class Array
{
public:
	Array(int length);
	Array(const Array& obj);
	~Array();

public:
	void setData(int index, int valude);
	int getData(int index);
	int length();

private:
	int m_length;
	int *m_space;

public:
	int &operator[](int i);
	bool operator==(Array& obj);
	bool operator!=(Array& obj);
	Array& operator=(Array& obj);
};

//要求重载以下操作符
// []  ==  !=  

myarray.cpp


#include "myarray.h"


Array::Array(int length)
{
	if (length < 0)
	{
		length = 0; //
	}

	m_length = length;
	m_space = new int[m_length];
}

//Array a2 = a1;
Array::Array(const Array& obj)
{
	this->m_length = obj.m_length;
	this->m_space = new int[this->m_length]; //分配内存空间

	for (int i=0; i<m_length; i++) //数组元素复制
	{
		this->m_space[i] = obj.m_space[i];
	}
}
Array::~Array()
{
	if (m_space != NULL)
	{
		delete[] m_space;
		m_space = NULL;
		m_length = -1;
	}
}

//a1.setData(i, i);
void Array::setData(int index, int valude)
{
	m_space[index] = valude;
}
int Array::getData(int index)
{
	return m_space[index];
}
int Array::length()
{
	return m_length;
}

int& Array::operator[](int i)
{
	if (i >= 0 && i < m_length)return m_space[i];
	abort();
}

bool Array::operator==(Array& obj)
{
	if (m_length != obj.m_length)return false;
	for (int i = 0; i < m_length; i++)
	{
		if (m_space[i] != obj.m_space[i])return false;
	}
	return true;
}

bool Array::operator!=(Array& obj)
{
	//if (m_length != obj.m_length)return true;
	//for (int i = 0; i < m_length; i++)
	//{
	//	if (m_space[i] != obj.m_space[i])return true;
	//}
	//return false;

	if (*this == obj)return false;
	return true;
}

Array& Array::operator=(Array& obj)
{
	//effcetive c++推荐的写法,改变语句顺序
	int* tmp = m_space;
	m_length = obj.m_length;
	m_space = new int[obj.m_length];
	for (int i = 0; i < m_length; i++)
	{
		m_space[i] = obj.m_space[i];
	}
	delete tmp;
	return *this;
}

myarray_test.cpp


#include <iostream>
using namespace std;
#include "myarray.h"

//类的框架设计完毕
//类的测试案例

//重载[]
//void operator[](int i)
//int operator[](int i);
//int& operator[](int i);
int main()
{
	Array  a1(10);

	for (int i=0; i<a1.length(); i++)
	{
		//a1.setData(i, i);
		//2 
		a1[i] = i;
		//
		//函数返回值当左值,需要返回一个引用
		//a1.operator [i]
	}

	cout<<"\n打印数组a1: ";
	for (int i=0; i<a1.length(); i++)
	{
		//cout<<a1.getData(i)<<" ";
		//1
		cout<<a1[i]<<endl;
	}
	cout<<endl;

	Array a2 = a1;
	cout<<"\n打印数组a2: ";
	for (int i=0; i<a2.length(); i++)
	{
		cout<<a2.getData(i)<<" ";
	}
	cout<<endl;

	//3
	Array a3(5);
	{
		a3 = a1;
		a3 = a2 = a1;

		cout<<"\n打印数组a3: ";
		for (int i=0; i<a3.length(); i++)
		{
			cout<<a3[i]<<" ";
		}

		//a3.operator=(a1)
		//Array& operator=(Array &a1)
	}
	

	//功能4
	
	if (a3 == a1)
	{
		printf("相等\n");
	}
	else
	{
		printf("不相等\n");
	}
	//a3.operator==(a1);
	//bool operator==(Array &a1);

	
	if (a3 != a1)
	{
		printf("不相等\n");
	}
	else
	{
		printf("相等\n");
	}
	//
	//a3.operator!=(a1)
	// bool operator!=(Array &a1);

	
	cout<<"hello..."<<endl;
	system("pause");
	return 0;
}

这边需要注意的是重载=号运算符的时候有可能会使用自身赋值给自身的情况,所以使用了effective c++书中的写法,改变了语句的顺序。这样可以保证将自身赋值给自身不会出现内存错误的情况。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值