C++基础:运算符重载

运算符重载

所谓重载,就是重新赋予新的含义

(1)简单使用

class Complex
{
public:
	Complex(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	
	void printCom()
	{
		cout << a << " + " << b << "i" << endl;
	}

	int a;
	int b;
};

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

void main()
{
	Complex c1(1, 2), c2(3, 4);
	Complex c3;

	// 运算符+ 重载
	c3 = c1 + c2;
	c3.printCom();

	system("pause");
}

(2)运算符重载的限制

不能重载的运算符

. :: .* ?: sizeof

(3)运算符重载的两种方法

  1. 全局函数 完成 +操作符 重载

二元运算符: Complex operator+(Complex &c1, Complex &c2)

一元运算符:Complex& operator++(Complex &c1)

  1. 类成员函数 完成 -操作符 重载

二元运算符: Complex operator-(Complex &c2)

一元运算符:Complex& operator--()

实现运算符(+、-、++、--、<<、=)重载

class Complex
{
public:
	Complex(int a = 0, int b = 0)
	{
		this->a = a;
		this->b = b;
	}
	
	void printCom()
	{
		cout << a << " + " << b << "i" << endl;
	}

	// 友元函数重载 +
	friend Complex operator+(Complex &c1, Complex &c2);
	// 友元函数重载 前置++
	friend Complex& operator++(Complex &c);
	// 友元函数重载 后置++
	friend Complex operator++(Complex &c, int);
	// 友元函数重载 <<
	//friend void operator<<(ostream &cout, Complex &c);
	friend ostream& operator<<(ostream &out, Complex &c);

	// 成员函数重载 -
	Complex operator-(Complex &c2)
	{
		Complex tmp(this->a - c2.a, this->b - c2.b);
		return tmp;
	}
	// 成员函数重载 前置--
	Complex& operator--()
	{
		this->a --;
		this->b --;
		return *this;
	}
	// 成员函数重载 后置--
	Complex operator--(int)
	{
		// 返回自身 *this
		Complex tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}
private:
	int a;
	int b;
};

// 使用全局函数(友元函数)实现 运算符 + 重载
Complex operator+(Complex &c1, Complex &c2)
{
	Complex tmp(c1.a + c2.a, c1.b + c2.b);
	return tmp;
}
// 使用全局函数(友元函数)实现 运算符前置++ 重载
Complex& operator++(Complex &c)
{
	c.a++;
	c.b++;
	return c;
}
// 使用全局函数(友元函数)实现 运算符后置++ 重载
// int 占位符,避免函数重载出错
Complex operator++(Complex &c, int)
{
	// 先返回,使用临时变量保存后再返回
	Complex tmp = c;
	c.a++;
	c.b++;
	return tmp;
}
// 使用全局函数(友元函数)实现 运算符 << 重载
// void operator<<(ostream &out, Complex &c)
// {
// 	out << c.a << " + " << c.b << "i" << endl;
// }
ostream& operator<<(ostream &out, Complex &c)
{
	out << c.a << " + " << c.b << "i" ;
	return out;
}

void main()
{
	Complex c1(1, 2), c2(3, 4);
	Complex c3, c4;

	// 二元运算符
	{
		// 使用全局函数(友元函数)实现 运算符+ 重载
		c3 = c1 + c2;
		cout << "operator+ : ";
		c3.printCom();

		// 使用成员函数 实现 运算符- 重载
		c4 = c1 - c2;
		cout << "operator- : ";
		c4.printCom();
	}
	
	// 一元运算符
	{
		// 使用全局函数(友元函数)实现 运算符前置++ 重载
		// ++a, 先++,(修改后)再返回自身
		// Complex& operator++(Complex &c)
		++c1;
		cout << "operator++ : ";
		c1.printCom();

		// 使用成员函数 实现 运算符前置-- 重载
		// Complex& operator--()
		--c2;
		cout << "operator-- : ";
		c2.printCom();

		// 使用全局函数(友元函数)实现 运算符后置++ 重载
		// a++, (修改前)先返回自身,再++
		// Complex operator++(Complex &c, int)
		c1++;
		cout << "operator++ : ";
		c1.printCom();

		// 使用成员函数 实现 运算符后置-- 重载
		// Complex operator--(int)
		c2--;
		cout << "operator-- : ";
		c2.printCom();
	}

	// 重载运算符 <<
	{
		// 使用全局函数(友元函数)实现 运算符 << 重载
		// << 参数1: cout 参数2:c1
		// cout定义: ostream cout, *_Ptr_cout;
		// void operator<<(ostream &out, Complex &c)
		//cout << c1;

		// 使用成员函数 实现 运算符 <<  重载
		// cout.operator --> 需在 ostream 类中定义成员函数,所以在这不能使用

		// 链式编程支持
		// 函数返回值当左值,需要返回一个引用
		// ostream& operator<<(ostream &out, Complex &c)
		cout << "operator<< : ";
		cout << c1 << "  test operator<<" << endl;
	}
	system("pause");
}

总结:

  1. 一般使用成员函数实现运算符重载

  2. 使用友元函数(全局函数)实现运算符重载的场景

    友员函数重载运算符常用于运算符的左右操作数类型不同的情况 ;

    在第一个参数需要隐式转换的情形下,使用友员函数重载运算符是正确的选择;

    C++中不能用友员函数重载的运算符有 : = () [] ->

(4)运算符重载提高

重载运算符 [] 、=、==、!=

重载赋值运算符=

class Name
{
public:
	Name(char* str)
	{
		len = strlen(str);
		pname = (char*)malloc(len + 1);
		strcpy(pname, str);
	}
	Name(const Name &obj)
	{
		len = obj.len;
		pname = (char*)malloc(len + 1);
		strcpy(pname, obj.pname);
	}
	~Name()
	{
		if (pname != NULL)
		{
			free(pname);
			pname = NULL;
			len = 0;
		}
	}

	// 重载 = 运算符,实现从浅拷贝到深拷贝
	// name3 = name1
	Name& operator=(Name &obj)
	{
		// 1. 释放旧的内存
		if (this->pname != NULL)
		{
			delete[] pname;
			len = 0;
		}
		// 2. 根据obj分配内存大小
		this->len = obj.len;
		this->pname = new char[len + 1];
		// 3. copy内存实现深拷贝
		strcpy(pname, obj.pname);
		// 返回 Name 自身
		return *this;
	}
private:
	char*	pname;
	int		len;
};

void test()
{
	Name name1("testname");
	Name name2 = name1;		// 编译器提供默认的拷贝构造函数

	// 重载 = 运算符,实现从浅拷贝到深拷贝
	// void operator=(Name &obj)
	// 支持链式编程  Name& operator=(Name &obj)
	Name name3("oldname");
	name3 = name1;
}

void main()
{
	test();
	system("pause");
}

总结:

  1. 赋值运算符重载用于对象数据的复制;
  2. operator= 必须重载为成员函数 ;
  3. 步骤:释放内存、得到大小、实现拷贝、返回引用;
  4. =操作符 从右向左;

重载函数调用符()

class MyClass
{
public:
	MyClass(int a=0, int b=0)
	{
		this->a = a;
		this->b = b;
	}
	int Func(int a, int b)
	{
		return (a*a + b*b);
	}
	int operator()(int a, int b)
	{
		return (a*a + b*b);
	}
private:
	int a;
	int b;
};

void main()
{
	// 构造函数
	MyClass c1(1, 2);
	// 成员函数
	MyClass c2;
	c2.Func(3, 4);
	// ()重载
	MyClass c3;
	c3(5, 6);

	system("pause");
}

为什么不要重载&&和||操作符

  1. &&和||是 C++中非常特殊的操作符;

  2. &&和||内置实现了短路规则

  3. 操作符重载是靠函数重载来完成的;

  4. 操作数作为函数参数传递;

  5. C++的函数参数都会被求值,无法实现短路规;

(5)运算符重载在项目开发中的应用

  1. 实现一个数组类:重载[] 、=、==、!=、<<、>>

注意:实际开发中应该将定义和实现分开。

// 实现一个数组类:实现重载[]、 =、 ==、 !=、 <<、 >>
class myArray
{
public:
	// 有参构造函数
	myArray(int length=0)
	{
		if (length < 0)
		{
			length = 0;
		}
		len = length;
		pSpace = new int[len];
	}
	// 拷贝构造函数
	myArray(const myArray &obj)
	{
		this->len = obj.len;
		this->pSpace = new int[this->len];
		for (int i = 0; i < len; i++)
		{
			this->pSpace[i] = obj.pSpace[i];
		}
	}
	// 析构函数
	~myArray()
	{
		if (pSpace != NULL)
		{
			delete[] pSpace;
			pSpace = NULL;
			len = -1;
		}
		cout << "执行析构函数" << endl;
	}

	int getLen()
	{
		return len;
	}

	// 重载 []
	int& operator[](int index)
	{
		return pSpace[index];
	}
	// 重载 =
	myArray& operator=(myArray &obj)
	{
		// 1. 释放旧的内存
		if (this->pSpace != NULL)
		{
			delete[] pSpace;
			len = 0;
		}
		// 2. 根据obj分配内存大小
		this->len = obj.len;
		this->pSpace = new int[len];
		// 3. copy内存实现深拷贝
		for (int i = 0; i < len; i++)
		{
			//pSpace[i] = obj.pSpace[i];
			pSpace[i] = obj[i];
		}
		// 返回 Name 自身
		return *this;
	}
	// 重载 ==
	bool operator==(myArray &obj)
	{
		if (this->len != obj.len)
		{
			return false;
		}
		for (int i = 0; i < len; i++)
		{
			if (pSpace[i] != obj[i])
			{
				return false;
			}
		}
		return true;
	}
	// 重载 !=
	bool operator!=(myArray &obj)
	{
		return !(*this == obj);
	}

	friend istream& operator >> (istream &in, myArray &obj);
	friend ostream& operator<<(ostream &out, myArray &obj);
private:
	int*	pSpace;
	int		len;
};


// 重载 >>
istream& operator >> (istream &in, myArray &obj)
{
	cout << "len: " << obj.len << endl;
	for (int i = 0; i < obj.len; i++)
	{
		printf("输入obj[%d]: ", i);
		cin >> obj[i];
	}
	return in;
}
// 重载 <<
ostream& operator<<(ostream &out, myArray &obj)
{
	for (int i = 0; i < obj.len; i++)
	{
		cout << obj[i] << " ";
	}
	return out;
}

// test
void testArr()
{
	// 有参构造函数
	myArray a(5);
	// 拷贝构造函数
	myArray b = a;
	myArray c(3);

	//重载运算符 []
	for (int i=0; i<a.getLen(); i++)
	{
		//int& operator[](int index)
		a[i] = i;
	}
	cout << a << endl;

	//重载运算符 =
	//myArray& operator=(myArray &obj)
	c = a;

	//重载运算符 ==
	//BOOL operator==(myArray &obj)
	if (a == c)
	{
		cout << "相等" << endl;
	}
	else
	{
		cout << "不相等" << endl;
	}

	//重载运算符 !=
	//BOOL operator!=(myArray &obj)
	if (a != c)
	{
		cout << "不相等" << endl;
	}
	else
	{
		cout << "相等" << endl;
	}

	//重载运算符 >> <<
	myArray d(3);
	//istream& operator>>(istream &in, myArray &obj)
	cin >> d;
	//ostream& operator<<(ostream &out, myArray &obj)
	cout << d << endl;
	cout << d << "--- "<< a << endl;
}

void main()
{
	testArr();
	system("pause");
}
  1. 实现一个字符串类:重载<< >> != == > < =

MyString.h

#pragma once
class MyString
{
public:
	// 构造
	MyString(int len=0);
	MyString(char* str);
	MyString(const MyString &str);

	// 重载 =
	MyString& operator=(const char* p);
	MyString& operator=(MyString &mystr);

	// 重载 []
	char& operator[](int index);

	// 重载 == !=
	bool operator==(const char* p);
	bool operator!=(const char* p);
	bool operator==(const MyString &mystr);
	bool operator!=(const MyString &mystr);

	// 重载 > <
	int operator>(const char* p);
	int operator<(const char* p);
	int operator>(const MyString &s);
	int operator<(const MyString &s);

	// 重载 <<
	friend ostream& operator<<(ostream &out, MyString &mystr);
	// 重载 >>
	friend istream& operator>>(istream &in, MyString &mystr);

	// 析构
	~MyString();
private:
	int		len;
	char*	str;
};

MyString.cpp

#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
#include "MyString.h"
// 无参构造函数
MyString::MyString(int len)
{
	if (len == 0)
	{
		len = 0;
		str = new char[len + 1];
		strcpy(str, "");
	}
	else
	{
		this->len = len;
		str = new char[len + 1];
		memset(str, 0, len);
	}
}

// 有参构造函数
MyString::MyString(char* str)
{
	if (str == NULL)
	{
		len = 0;
		str = new char[len + 1];
		strcpy(str, "");
	}
	else
	{
		len = strlen(str);
		this->str = new char[len + 1];
		strcpy(this->str, str);
	}
}

// 拷贝构造函数
MyString::MyString(const MyString &str)
{
	this->len = str.len;
	this->str = new char[len + 1];
	strcpy(this->str, str.str);
}

// 析构函数
MyString::~MyString()
{
	if (str != NULL)
	{
		delete[] str;
		str = NULL;
		len = 0;
	}
}

// 重载 = 
// 情况一: s = "aaa";
MyString& MyString::operator=(const char* p)
{
	// 1. 释放旧的内存
	if (this->str != NULL)
	{
		delete[] str;
		len = 0;
	}
	// 2. 根据p分配内存大小
	if (p == NULL)
	{
		len = 0;
		str = new char[len + 1];
		strcpy(str, "");
	}
	else
	{
		// 3. copy内存
		this->len = strlen(p);
		this->str = new char[len + 1];
		strcpy(str, p);
	}
	// 返回自身
	return *this;
}
// 情况二: s2 = s1;
MyString& MyString::operator=(MyString &mystr)
{
	if (this->str != NULL)
	{
		delete[] str;
		len = 0;
	}

	this->len = mystr.len;
	this->str = new char[len + 1];
	strcpy(str, mystr.str);

	return *this;
}

// 重载 []
char& MyString::operator[](int index)
{
	return str[index];
}

// 重载 <<
ostream& operator<<(ostream &out, MyString &mystr)
{
	cout << mystr.str;
	return out;
}
// 重载 >>
istream& operator >> (istream &in, MyString &mystr)
{
	cin >> mystr.str;
	return in;
}

// 重载 == !=
// 情况一: s2 == "aaa";
bool MyString::operator==(const char* p)
{
	if (p == NULL)
	{
		if (len == 0)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		if (len != strlen(p))
		{
			return false;
		}
		else
		{
			return !(strcmp(str, p));
		}
	}
}
bool MyString::operator!=(const char* p)
{
	return !(*this == p);
}
// 情况二: s1 == s2;
bool MyString::operator==(const MyString &mystr)
{
	if (len != mystr.len)
	{
		return false;
	}
	return !strcmp(str, mystr.str);
}
bool MyString::operator!=(const MyString &mystr)
{
	return !(*this == mystr.str);
}

// 重载 > <
// 情况1: s > "aaaa";
int MyString::operator>(const char* p)
{
	return strcmp(this->str, p);
}
int MyString::operator<(const char* p)
{
	return strcmp(p, this->str);
}
// 情况2: s1 > s2
int MyString::operator>(const MyString &s)
{
	return strcmp(this->str, s.str);
}
int MyString::operator<(const MyString &s)
{
	return strcmp(s.str, this->str);
}

MyString_Test.cpp

#include "iostream"
using namespace std;
#include "MyString.h"

void test()
{
	// 构造函数
	MyString s1;
	MyString s2("testS2");
	MyString s3 = s2;
	MyString s4 = "S4_test";
	
	// 重载 =
	{
		//MyString& operator=(const char* p)
		//MyString& operator=(MyString &mystr)
		s2 = s4;
		s2 = "ttttt22222";
	}	
	// 重载 []
	{
		//char& operator[](int index)
		s2[2] = '6';
		cout << "修改后: " << s2[2] << endl;
	}
	// 重载 <<
	{
		//ostream& operator<<(ostream &out, MyString &mystr)
		cout << "修改后: " << s2 << endl;
	}
	// 重载 == !=
	{
		// 情况一: s2 == "aaa";
		//bool operator==(const char* p)
		//bool operator!=(const char* p)
		if (s2 == "tt6tt22222")
		{
			cout << "相等" << endl;
		}
		else
		{
			cout << "不相等" << endl;
		}
		if (s2 != "ss22")
		{
			cout << "不相等" << endl;
		}
		else
		{
			cout << "相等" << endl;
		}
		// 情况二: s1 == s2;
		//bool operator==(const MyString &mystr)
		//bool operator!=(const MyString &mystr)
		MyString s5 = "tt6tt22222";
		if (s2 == s5)
		{
			cout << "相等" << endl;
		}
		else
		{
			cout << "不相等" << endl;
		}
		if (s2 != s4)
		{
			cout << "不相等" << endl;
		}
		else
		{
			cout << "相等" << endl;
		}
	}
	// 重载 > <
	{
		MyString a("aaaa");
		MyString b("bbbb");

		// >时返回整数,<时返回负数
		//int tag = (b > "aaaa");
		int tag = (a > b);
		if (tag > 0)
		{
			cout << "大于" << endl;
		}
		else if(tag == 0)
		{
			cout << "等于" << endl;
		}
		else
		{
			cout << "小于" << endl;
		}
	}
	// 重载 >>
	{
		MyString str1(128);
		//istream& operator >> (istream &in, MyString &mystr)
		cout << "输入字符串(回车确认):";
		cin >> str1;
		cout << str1;
	}
}
void main()
{
	test();
	system("pause");
}

猜你喜欢

转载自www.cnblogs.com/2dx3906/p/13166930.html