重载赋值运算符
重载<<和>>
重载[]
重载()
重载二元算术运算符
重载赋值运算符
默认赋值运算符重载
在一个类中,编译器会自动为你的类添加一个默认赋值运算符重载的函数
假设有类
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=”必须是成员函数
{}
重载赋值运算符的格式
赋值运算符不一定要写为返回引用或者传递引用
一般约定为传递引用或者返回引用的主要原因是要针对以下情况:
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
}