重载各式运算符

文章详细介绍了C++中如何重载赋值运算符、流操作符<<和>>、数组访问运算符[]以及函数调用运算符()。强调了重载赋值运算符时通常返回引用以及为何这样设计的原因,同时也提到了二元算术运算符的重载方法,包括作为成员函数和全局函数的情况。此外,还讨论了内存管理在重载运算符中的应用,如避免浅拷贝问题。
摘要由CSDN通过智能技术生成
  • 重载赋值运算符

  • 重载<<和>>

  • 重载[]

  • 重载()

  • 重载二元算术运算符

重载赋值运算符

默认赋值运算符重载

在一个类中,编译器会自动为你的类添加一个默认赋值运算符重载的函数

假设有类

class Role{}

编译器默认添加

class Role
{
public:
Role& operator=(const Role& role);
}
class Role
{
public:
	int hp;
	int mp;
};

int main()
{
	Role x, y;
	x.hp = 100;
	x.mp = 200;
	y = x;
	std::cout << y.hp << " " << y.mp << std::endl;//100  200
}
________________________________________________________________________________
class Role
{
public:
	int hp;
	int mp;
	Role& operator=(const Role& role)//编译器添加的默认赋值运算符重载
	{
		hp = role.hp;
		mp = role.mp;
		return *this;//返回值是引用,所以返回*this指针
	}
};
——————————————————————————————————————————————————————————————————————————————————
class Role
{
public:
	int hp;
	int mp;
	Role& operator=(const Role& role)=delete;//删除默认赋值运算符重载
};

int main()
{
	Role x, y;
	x.hp = 100;
	x.mp = 200;
	y = x;//报错
	std::cout << y.hp << " " << y.mp << std::endl;
}

实现赋值运算符重载

*赋值运算符的重载必须用成员函数的方式实现(不能写为全局函数)

class hstring
{
	char* c_str;
	short length;
public:
	hstring& operator=(const hstring& hstring);
}
hstring& hstring::operator=(const hstring& hstring)
{……}
————————————————————————————————————————————————————————————————————————————————————————
class Role
{
public:
	int hp;
	int mp;
	Role& operator=(const Role& role)=delete;
};
Role& operator=(const Role& role)//报错,“operator=”必须是成员函数
{}

重载赋值运算符的格式

  1. 赋值运算符不一定要写为返回引用或者传递引用

  1. 一般约定为传递引用或者返回引用的主要原因是要针对以下情况:

htsring x,y,z;
x=y=z;
//相当于:
x=(y=z);
//相当于
x.operator=(y.operator=(z));

因此返回引用和传递引用成为最好的选择

class hstring
{
	char* cstr;
	unsigned short uslen;//字符串长度
public:
	char* c_str() { return cstr; }
	hstring(const char* str);//构造函数,利用c字符串来构造hstring
	hstring(const hstring& str);//副本构造函数,利用hstring来构造hstring
};

hstring::hstring(const char* str)
{
	cstr = (char*)str;
}


int main()
{
	char strA[]{ "aabbcc" };
	hstring str{ strA };
	strA[0] = 0;
	std::cout << str.c_str();//不输出任何东西
    //问题就在初始化时这块内存根本就不是str的,是strA的
}
class hstring
{
	char* cstr;//字符串内容
	unsigned short uslen;//字符串长度
	unsigned short usmlen;//字符串的内存长度
	unsigned short GetLenth(const char* str)const;
	void CopyStrs(char* dest, const char* source);
public:
	char* c_str() { return cstr; }
	~hstring();//析构函数
	hstring();//构造函数
	hstring(const char* str);//构造函数,利用c字符串来构造hstring
	hstring(const hstring& str);//副本构造函数,利用hstring来构造hstring
	hstring& operator=(const hstring& str);
};

hstring::~hstring()
{
	if (cstr != nullptr)delete[] cstr;
}

hstring::hstring()
{
	usmlen = 0x32;
	uslen = 0;
	cstr = new char[usmlen];//为cstr设置缓冲区(50字节以内不用重新分配内存空间)
}

hstring::hstring(const char* str):hstring()
{
	CopyStrs(cstr, str);
}

hstring::hstring(const hstring& str) : hstring()
{
	CopyStrs(cstr, str.cstr);
}

unsigned short hstring::GetLenth(const char* str)const
{
	unsigned  short len = 0;
	for (; str[len++];);
	return len;
}

void hstring::CopyStrs(char* dest, const char* source)
{
	unsigned short len = GetLenth(source);
	if (len > usmlen)//需要重新分配内存空间
	{
        char* lstr = cstr;
		cstr = new char[slen];
		usmlen = slen;
		memcpy(cstr, lstr, uslen);
		delete[] lstr;//删除内存,防止内存泄露en];
		usmlen = len;
	}
	memcpy(cstr, source, len);
	uslen = len;//字符串长度修正
}

hstring& hstring::operator=(const hstring& str)
{
	CopyStrs(cstr, str.cstr);
	return *this;
}

int main()
{
	char strA[]{ "aabbcc" };
	hstring str=strA;//调用副本构造函数,因为str还没有
	hstring str1{ str };
	hstring str2 = str1;
	strA[0] = 0;
	std::cout << str.c_str()<<std::endl;//aabbcc
	std::cout << str1.c_str() << std::endl;//aabbcc
	std::cout << str2.c_str() << std::endl;//aabbcc
	str1 = "1111";//调用的是hstring& hstring::operator=(const hstring& str)
    //先用"1111"构建hstring类型的临时变量,然后传入这个临时变量
}

重载赋值运算符和副本构造函数

hstring str=“123123”;//副本构造函数

hstring str1=str;//副本构造函数

str1=str;//默认构造函数

重载<<和>>

<<和>>可以重载为类的方法或者是全局函数

方法:

返回类型 operator>>(类型 操作数);

全局函数

返回类型 operator>>(类型 左操作数, 类型 右操作数);

hstring& hstring::operator<<(const hstring& str)
{
	unsigned short slen = GetLenth(str.cstr);
	slen = uslen + slen - 1;
	if ((uslen + slen - 1) > usmlen)//-1是去除字符串结尾0的长度
	{
		delete[] cstr;//删除内存,防止内存泄露
		cstr = new char[slen];
		usmlen = slen;
	}
	memcpy(cstr+uslen-1, str.cstr,slen-uslen+1 );
	//cstr+uslen恰好是0的位置
	uslen = slen;//字符串长度修正
	return *this;
}

int main()
{
	hstring str{ "123" };
	str << "1111" << "2222" << "3333";
}
——————————————————————————————————————————————————————————————————————————————————

//std::cout是std::ostream类型
std::ostream& operator<<(std::ostream& _cout, hstring _str)
{
	_cout << _str.c_str();
	return _cout;
}

//std::cin是std::istream类型
std::istream& operator>>(std::istream& _cin, hstring& _str)
{
	char _sRead[0x1FF]{};
	_cin >> _sRead;
	_str = _sRead;

	return _cin;
}

int main()
{
	hstring str{ "123" };
	str << "1111" << "2222" << "3333";
	std::cout << str.c_str()<<std::endl;//123111122223333
	std::cout << str << "555";//就不用写str.c_str()了
	//"555"使用的是std::ostream& operator<<(std::ostream& _cout, hstring _str)
	//相当于operator<<( operator<<(std::cout,str) , "555") 
    std::cin >> str;
}

重载[]

[]只能重载为类的方法

方法: 返回类型 operator [] ( 类型 操作数 );

hstring str = "Hello";
str[1];//报错,没有与这些操作数匹配的"[]"运算符
//#define hstring_no_char -1

class hstring
{
	char* cstr;//字符串内容
	unsigned short uslen;//字符串长度
	unsigned short usmlen;//字符串的内存长度
	unsigned short GetLenth(const char* str)const;
	void CopyStrs(char* dest, const char* source);
public:
	inline static char nochar = -1;//nochar
	char* c_str() { return cstr; }
	~hstring();//析构函数
	hstring();//构造函数
	hstring(const char* str);//构造函数,利用c字符串来构造hstring
	hstring(const hstring& str);//副本构造函数,利用hstring来构造hstring
	hstring& operator=(const hstring& str);
	hstring& operator<<(const hstring& str);
	const char& operator[](const unsigned short index) const;
};

const char& hstring::operator[](const unsigned short index) const
{
	if (index < uslen)  return cstr[index];
	//else return hstring_no_char;
	else return nochar;
}

int main()
{
	hstring str = "Hello";
	std::cout << str;//helo
	std::cout << str[2];//l
	//if (str[1000] == hstring_no_char)
	if(str[1000]==hstring::nochar)
	{
		std::cout << "越界";
	}
}

重载()

()只能重载为类的方法

方法: 返回类型 operator()(类型 操作数);

● ()重载称为functor函数对象

● ()不限制参数个数

● ()可以拥有默认实参

利用()实现二维数组模式的访问方式

char hstring::operator()(const int ,const int);
hstring str1;
str(1,2)
std::ostream& operator<<(std::ostream& _cout, hstring& _str)
{
	_cout << _str.c_str();
	return _cout;
}
std::ostream& operator<<(std::ostream& _cout, hstring&& _str)//右值引用
{
	_cout << _str.c_str();
	return _cout;
}

const char& hstring::operator()()
{
	return cstr[0];
}

hstring hstring::operator()(const unsigned short start, const unsigned length)
{
	if (start > uslen-2) //不允许截取末尾的/0
		return hstring("");
	unsigned slen = start + length > uslen - 1 ? uslen - start - 1 : length;
	char* newstr = new char[slen + 1];
	memcpy(newstr, cstr+start, slen + 1);
	newstr[slen] = 0;
	return hstring(newstr);
}

int main()
{
	hstring str = "Hello";
	std::cout << str();//H
	std::cout << str(1, 2);//el
}

重载二元算术运算符

二元算术运算符+-*/%可以重载为类的成员函数或者是全局函数

类的成员函数

返回类型operator运算符(类型操作数);

全局函数

返回类型operator运算符(类型左操作数,类型右操作数);

int val = 123123123;
	char str[12]{};
	int len = { 11 };
	bool bfs = val < 0;

	if (bfs < 0)val = -1 * val;
	do
	{
		str[--len] = val % 10 + 48;
		val /= 10;
	} while (val);
	if (bfs)str[--len] = '-';
	std::cout << &str[len];

——————————————————————————————————————————————————————————————————————————————————————
//精简代码,去if:
int val = -123123123;
char str[12]{};//int类型最大长度
char len = { 11 };
bool bzs = val >= 0;

//如果正数,val=val*1,如果负数,val=val*-1
//bzs=false=0时要得到-1,bzs=true=1时要得到1
//所以val=val*(bzs*2-1)

val = val * (bzs * 2 - 1);

do
{
    str[--len] = val % 10 + 48;
} while (val /= 10);

//如果是负数(bzs=0),len=len-1,如果是正数(bzs=1),len=len
//所以len=len-!bzs或len=len-(1-bzs)

//bzs=0 | '-'*(bzs+1)*(1-bzs) + str[len]*bzs
//bzs=1 | '-'*(bzs+1)*(1-bzs) + str[len]*bzs

str[len = len - 1 * (1 - bzs)] = '-' * (bzs + 1) * (1 - bzs) + str[len] * bzs;


std::cout << &str[len];
}
hstring& hstring::operator+(int val)
{
	char str[12]{};//定义一段内存长度
	char len = { 11 };//长度
	bool bzs = val >= 0;//是不是正数

	val = val * (bzs * 2 - 1);//取绝对值

	do
	{
		str[--len] = val % 10 + 48;
	} while (val /= 10);

	str[len = len - 1 * (1 - bzs)] = '-' * (bzs + 1) * (1 - bzs) + str[len] * bzs;

	unsigned short slen = uslen + (12 - len-1);//减去结尾0
    //uslen中包含结尾0,(12-len)中包含结尾0,所以要减一,不然算了两次

	if (slen > usmlen)
	{
		char* lstr = cstr;
		cstr = new char[slen];
		memcpy(cstr, lstr, uslen);
		delete[] lstr;
	}

	//     cstr+uslen是0的位置,所以要减一
	memcpy(cstr + uslen-1, str+len, 12 - len);
	uslen = slen;

	return *this;
}

int main()
{
	hstring str{ "123" };
	str = str + -456 + 789;
	std::cout << str;//123-456789
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值