重载运算符(operator)

什么是运算符重载

重载我们分析过了,就是对一个已有的函数,使其参数的个数,类型不同来赋予新的含义,实现新的功能。那么运算符也可以被重载赋予新的含义和功能。这就运算符重载。

为什么会用运算符重载机制

我们在开发中都使用过运算符,一般情况下我们接触最多的就是加减乘除,还有new,delete这些运算法,直接使用他们只能对单一类型的数据进行操作。例如我们想对自定义类型进行运算操作时,该怎么办呢?重载运算符就显得极其重要了。

#pragma warning(disable : 4996)
#include <iostream>
using namespace std;

class Complex
{
    friend Complex Add(Complex &c1, Complex &c2);
    friend Complex operator+(Complex &c1, Complex &c2);
public:
    Complex(int a, int b)
    {
        this->m_a = a;
        this->m_b = b;
    }
    //成员函数(在类的内部完成两个数据的和)
    int GetAdd()
    {
        return m_a + m_b;
    }
    //成员函数(在类的内部完成两个类的数据的和)
    Complex GetAdd(Complex &c1)
    {
        Complex temp = Complex(this->m_a + c1.m_a, this->m_b + c1.m_b);
        return temp;
    }
private:
    int m_a, m_b;
};

//全局函数(要访问类的私有成员可以使用友元friend)
Complex Add(Complex &c1,Complex &c2)
{
    Complex temp = Complex(c1.m_a + c2.m_a, c1.m_b + c2.m_b);
    return temp;
}

//重载“+”运算法
Complex operator+(Complex &c1, Complex &c2)
{
    Complex temp = Complex(c1.m_a + c2.m_a, c1.m_b + c2.m_b);
    return temp;
}

int main()
{
    //使用成员函数
    Complex c1(1, 2), c2(3, 4);
    int a1 = c1.GetAdd();
    int a2 = c2.GetAdd();
    int a3 = a1 + a2;
    cout << "c1与c2的和 = " << a3 << endl;

    //使用成员函数
    Complex c3 = c1.GetAdd(c2);
    int a4 = c3.GetAdd();
    cout << "c1与c2的和 = " << a4 << endl;

    //使用友元函数
    Complex c4 = Add(c1, c2);
    int a5 = c4.GetAdd();
    cout << "c1与c2的和 = " << a5 << endl;

    //使用"operator+"重载运算符
    Complex c5 = c1 + c2;
    int a6 = c5.GetAdd();
    cout << "c1与c2的和 = " << a5 << endl;
    system("pause");
    return 0;
}

看上面的例子,如果我们想对同一类型的两个对象的数据成员进行加法运算时,可以用很多种方式达到其目的,有成员函数,友元函数,同样可以重载运算符达到其目的。

 Complex c5 = c1 + c2

原因Complex是用户自定义类型,编译器根本不知道如何进行相加。可是编译器给我们提供了一种机制,让我们自己去完成自定义类型的相加操作,而这一机制就是运算符重载机制。

运算符重载的限制

可以重载的运算符

+     -     *     /     %     ^     &     |     ~

!     =     <     >     +=    -=    *=    /=    %=

^=    &=    |=    <<    >>    >>=   <<=   ==    !=

<=    >=    &&    ||    ++    --    ->*    ‘    ->

[]    ()    new   delete     new[]     delete[]

不能重载的运算符

.	::	 .*	 ?:	 sizeof

重载运算符函数可以对运算符做出新的解释,但原有基本语义不变

  • 不改变运算符的优先级
  • 不改变运算符的结合性
  • 不改变运算符所需的操作数
  • 不能创建新的运算符

运算符重载规则

运算符函数是一种特殊的成员函数或友元函数(运算符重载的本质是一个函数

类型 类名 :: operator  op(参数表){}
返回值       关键字    函数名(操作数) 

全局函数、类成员函数方法实现运算符重载步骤

  1. 要承认操作符重载是一个函数,写出函数名称operator op ()
  2. 根据操作数,写出函数参数
  3. 根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务

运算符重载的两种方法

用成员或友元函数重载

  • 运算符函数可以重载为成员函数或友元函数
  • 关键区别在于成员函数具有this指针,友元函数没有this指针
  • 不管使用成员函数或友元函数重载运算符,其使用方法相同,但传递参数的方式不同,实现代码不同,应用场合不同

例:字符串类的封装以及业务实现

// MyString.h

#pragma once
#include <iostream>
using namespace std;
#pragma warning(disable : 4996)

class MyString
{
	friend ostream & operator<<(ostream &out, MyString &s);
	friend istream & operator>>(istream &input, MyString &s);
public:
	MyString(const char *s );
	MyString(int len = 0);
	MyString(const MyString &obj);
	void MyPrint();
	~MyString();
public:
	MyString & operator=(const MyString &obj);
	MyString & operator=(const char *s);
	char &operator[](int index)const;

public:
	bool operator==(const char *str)const;
	bool operator!=( const char *str)const;
	bool operator==(const MyString &s)const;
	bool operator!=(const MyString &s)const;

	/*bool operator<(const char *str)const;
	bool operator>(const char *str)const;
	bool operator<(const MyString &s)const;
	bool operator>(const MyString &s)const;*/

public:
	char * Str();
	const char *c_Str();
	int Length();
	

private:
	char *str;
	int m_len;
};

//MyString.cpp

#include "MyString.h"

MyString::MyString(const char *s)
{
	if (s == NULL)
	{
		this->m_len = 0;
		this->str = new char[m_len + 1];
		strcpy(str, "");
	}
	else
	{
		this->m_len = strlen(s);
		cout << m_len << endl;
		this->str = new char[m_len + 1];
		strcpy(str, s);
	}
}

MyString::MyString(int len)
{
	if (len == 0)
	{
		this->m_len = 0;
		this->str = new char[m_len + 1];
		strcpy(str, "");
	}
	else
	{
		this->m_len = len;
		this->str = new char[m_len + 1];
		memset(this->str, 0, m_len);
	}
}

MyString::MyString(const MyString & obj)
{
	this->m_len = obj.m_len;
	this->str = new char[m_len + 1]; 
	strcpy(str, obj.str);
}

void MyString::MyPrint()
{
	cout << str << endl;
}


MyString::~MyString()
{
	if (this->str != NULL)
		delete[] str;
	this->m_len = 0;
}

MyString & MyString::operator=(const MyString &obj)
{
	if (this->str != NULL)
	{
		delete[] str;
		m_len = 0;
	}
	this->m_len = obj.m_len;
	this->str = new char[m_len+1];
	strcpy(str, obj.str);
	return *this;
}

MyString& MyString::operator=( const char *s)
{
	if (this->str != NULL)
	{
		delete[] str;
		m_len = 0;
	}
	if (s == NULL)
	{
		m_len = 0;
		str = new char[m_len + 1];
		strcpy(str, "");
	}
	else
	{
		m_len = strlen(s);
		str = new char[m_len + 1];
		strcpy(str, s);
	}
	return *this;
}

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

bool MyString::operator==(const char * str)const
{
	if (str == NULL)
	{
		if (this->m_len == 0)
			return true;
		else
			return false;
	}
	else
	{
		if (this->m_len == strlen(str))
		{
			 return !strcmp(this->str, str);
		}
		else
		{
			return false;
		}
	}
}

bool MyString::operator!=(const char * str)const
{
	return !(*this == str);
}

bool MyString::operator==(const MyString & s)const
{
	if (m_len != s.m_len)
		return false;
	else
	{
		return !strcmp(this->str, s.str);
	}
}

bool MyString::operator!=(const MyString & s)const
{
	return !(*this == s);
}

char * MyString::Str()
{
	return this->str;
}

const char * MyString::c_Str()
{
	return this->str;
}

int MyString::Length()
{
	return this->m_len;
}

//bool MyString::operator<(const char * str) const
//{
//	return strcmp(this->str, str );
//}
//
//bool MyString::operator>(const char * str) const
//{
//	return strcmp(str, this->str);
//}
//
//bool MyString::operator<(const MyString & s) const
//{
//	return strcmp(this->str, s.str);
//}
//
//bool MyString::operator>(const MyString & s) const
//{
//	return strcmp(s.str, this->str);
//}

ostream & operator<<(ostream & out, MyString & s)
{
	return out << s.str;
}

istream & operator>>(istream & input, MyString & s)
{
	return input >> s.str;
}

总结

1、对于自定义类型进行运算时,我们会使用到运算符重载

2、成员函数和友元函数都可以重载运算符,其参数,代码实现,应用场景不同

3、运算符的重载符合运算符的优先级,结合性,操作数。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值