运算符重载
运算符重载的概念
运算符重载类似于函数重载。
运算符重载允许把标准运算符(如+
、-
、*
、<
等)应用于定制数据类型的对象。
什么情况下需要考虑运算符重载?
需要用运算符操作自定义类的对象时,如对象之间直观自然,可以提高比较大小等,通过重载支持类的运算。
运算符重载:①体现了程序的可读性;②体现了C++的可扩充性
运算符重载的定义
作为类的成员函数或友元函数、作为一般函数(很少用)。
1、成员函数原型的格式:
函数类型 operator 运算符(参数表);
成员函数定义的格式:
函数类型 类名::operator 运算符(参数表)
{
函数体;
}
以成员函数的方式重载运算符
-单目运算符:不带参数,该类对象为唯一操作数
-双目运算符:带一个参数,该类对象为左操作数、参数为右操作数
2、友元函数原型的格式:
friend 函数类型 operator 运算符(参数表);
友元函数定义的格式:
函数类型 operator 运算符(参数表)
{
函数体;
}
以友元函数的方式重载运算符
-单目运算符:带一个参数,该参数为唯一操作数,是自定义类的对象 ++(a)
-双目运算符:带两个参数,第一个参数为左操作数、第二个参数为右操作数,至少有一个参数为自定义类的对象
+(a, b)
实例
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double = 0.0, double = 0.0);
Complex operator+(const Complex&) const;
Complex Add(const Complex&) const;
Complex operator-(const Complex&) const;
Complex& operator=(const Complex&);
void print() const;
private:
double real; // real part
double imaginary; // imaginary part
};
Complex::Complex(double r, double i)
{
real = r;
imaginary = i;
}
Complex Complex::operator+(const Complex &operand2) const
{
Complex sum;
sum.real = this->real + operand2.real;
sum.imaginary= this->imaginary + operand2.imaginary;
return sum;
}
Complex Complex::Add(const Complex &operand2) const
{
//功能的实现同上
}
Complex Complex::operator-(const Complex &operand2) const
{
Complex diff;
diff.real = real - operand2.real;
diff.imaginary=imaginary - operand2.imaginary;
return diff;
}
Complex& Complex::operator=(const Complex &right)
{
real = right.real;
imaginary = right.imaginary;
return *this; // enables concatenation
}
void Complex::print() const
{
cout<<'('<<real<< "," << imaginary << ')';
}
int main()
{
Complex x, y(4.3, 8.2), z(3.3, 1.1);
cout << "x: "; x.print();
cout << "\ny: "; y.print();
cout << "\nz: "; z.print();
x = y + z; //比表达式x=y.Add(z);更简练,更直观
cout << "\n\nx = y + z:\n"; x.print();
cout << " = "; y.print();
cout << " + "; z.print();
return 0;
}
执行结果:
x: (0,0)
y: (4.3,8.2)
z: (3.3,1.1)
x = y + z:
(7.6,9.3) = (4.3,8.2) + (3.3,1.1)
运算符重载的规则
①运算符重载不允许发明新的运算符。
②不能改变运算符操作对象的个数。
③运算符被重载后,其优先级和结合性不会改变。
④不能重载的运算符:
一元运算符重载
操作数是自定义类的对象或对象的引用。
作为成员函数重载没有参数。
作为友元函数重载参数为自定义类的对象或对象的引用(概念介绍)。
实例
(成员函数的方式重载!)
#include <iostream>**自增、自减运算符重载**
#include <string.h>
using namespace std;
class CString
{
public:
CString(const char *s="");
CString(const CString& s);
~CString();
CString& operator = (const CString& s);
CString& operator = (const char *s);
bool operator !();
char *m_str;
private:
int m_size;
};
CString::CString(const CString& s)
{
m_size=strlen(s.m_str);
m_str=new char[m_size+1];
strcpy(m_str,s.m_str);
}
CString::CString(const char *s/* ="" */)
{
m_size=strlen(s);
m_str=new char[m_size+1];
strcpy(m_str,s);
}
bool CString::operator !()
{
if (strlen(m_str)==0)
{
return true;
}
else
return false;
}
CString::~CString()
{
delete []m_str;
}
int main()
{
CString s1, s2("some string");
if (!s1)//括号中等价于s1.operator!()=>显示调用
cout<<"s1 is NULL!"<<endl;
else cout<<"s1 is not NULL!"<<endl;
if (!s2)
cout<<"s2 is NULL!"<<endl;
else
cout<<"s2 is not NULL!"<<endl;
return 0;
}
执行结果:
s1 is NULL!
s2 is not NULL!
自增、自减运算符重载
在C++中,单目运算符有++和- -,它们是变量自动增1和自动减1的运算符。在类中可以对这两个单目运算符进行重载。
前置自增和前置自减的重载:
1、成员函数的方式重载,原型为:
函数类型 & operator++();
函数类型 & operator--();
2、友元函数的方式重载,原型为:
函数类型 & operator++(类类型 &);
函数类型 & operator--(类类型 &);
后置自增和后置自减的重载:
1、成员函数的方式重载,原型为:
函数类型 operator++(int);
函数类型 operator--(int);
2、友元函数的方式重载,原型为:
函数类型 operator++(类类型 &,int);
函数类型 operator--(类类型 &,int);
使用前缀运算符的语法格式:++<对象>;
使用后缀运算符的语法格式:<对象>++;
实例
#include <iostream>
using namespace std;
class CInt
{
public:
CInt(int a=0);
void Print();
CInt &operator ++();
CInt operator ++(int);
private:
int i;
};
CInt::CInt (int a)
{
i = a;
}
void CInt::Print()
{
cout << "i=" << i << endl;
}
CInt &CInt::operator ++()
{
++i;
return *this;
}
CInt CInt::operator ++(int)
{
CInt sum;
sum=*this;
++i;
return sum;
}
int main(void)
{
CInt a(5), b(5), c, d;
c = a++;
d = ++b;
cout << "a: ";a.Print();
cout << "b: ";b.Print();
cout << "c: ";c.Print();
cout << "d: ";d.Print();
return 0;
}
执行结果:
a: i=6
b: i=6
c: i=5
d: i=6
二元运算符重载
1、成员函数的方式重载二元运算符
函数原型:
函数类型 operator 二元运算符(类型 参数);
带有一个参数
左操作数必须为该类的对象或对象的引用
2、二元运算符重载为带有两个参数的非成员函数
函数原型:
函数类型 operator 二元运算符(类型 参数1,类型 参数2);
参数之一必须是类的对象或对象的引用
赋值运算符的重载
1、赋值运算符可直接用在自定义类的对象赋值。
2、如果没有提供重载的赋值运算符函数来复制类的对象。编译器就会提供默认版本的operator=()
。
3、赋值运算符的默认版本会简单地进行逐个成员的复制过程,类似于默认的拷贝构造函数。
4、运算符“=”重载时,要检查两个操作数是否为同一个对象。
5、如果对象中包含动态分配的空间,这种赋值方式就不合适了,如:
CString s1("abc"), s2("def"); //具体类见一元运算符重载实例
s1 = s2;
赋值的结果是:对象s1和s2的指针str都指向了同一块数据空间。
6、对象中包含动态分配的空间,赋值运算符需要自己重载,函数实现的算法与拷贝构造函数类似。
实例
#include <iostream>
#include <string.h>
using namespace std;
class CString
{
public:
CString(const char *s="");
CString(const CString& s);
CString & operator = (const CString & s);
CString & operator = (const char *s);
char *m_str;
private:
int m_size;
};
CString::CString(const CString& s)
{
m_size=strlen(s.m_str);
m_str=new char[m_size+1];
strcpy(m_str,s.m_str);
}
CString::CString(const char *s/* ="" */)
{
m_size=strlen(s);
m_str=new char[m_size+1];
strcpy(m_str,s);
}
CString& CString::operator =(const CString& str)
{
if (this!=&str)
{
delete[] m_str;
m_size=strlen(str.m_str);
m_str=new char[m_size+1];
strcpy(m_str,str.m_str);
}
return *this;
}
CString& CString::operator =(const char *str)
{
delete[] m_str;
m_size=strlen(str);
m_str=new char[m_size+1];
strcpy(m_str,str);
return *this;//为什么需要返回值?
}
int main()
{
CString s1("abc"),s2(s1),s3;
s3=s2;
cout<<"s1:"<<s1.m_str<<endl; //m_str应该声明成私有,如何输出
cout<<"s2:"<<s2.m_str<<endl; //cout<<s2;
cout<<"s3:"<<s3.m_str<<endl;
s3="tom";
cout<<"s3:"<<s3.m_str<<endl;
return 0;
}
执行结果:
s1:abc
s2:abc
s3:abc
s3:tom
‘+’运算符重载的使用
实例
#include <iostream>
#include <string.h>
#include <windows.h>
using namespace std;
class CString
{
public:
CString(const char *s="");
CString(const CString& s);
CString operator + (const CString &s);
CString operator + (const char *s);
CString & operator = (const CString & s);
CString & operator = (const char *s);
char *m_str;
private:
int m_size;
};
CString::CString(const CString& s)
{
m_size=strlen(s.m_str);
m_str=new char[m_size+1];
strcpy(m_str,s.m_str);
}
CString::CString(const char *s/* ="" */)
{
m_size=strlen(s);
m_str=new char[m_size+1];
strcpy(m_str,s);
}
CString CString::operator+(const CString &s)
{
CString tempStr;
char *p=new char[strlen(this->m_str)+strlen(s.m_str)+1];
if(p==NULL){exit(1);}
strcpy(p,this->m_str);
strcat(p,s.m_str);
tempStr.m_str=p;
return tempStr;
}
CString CString::operator+(const char *s)
{
CString tempStr;
char *p=new char[strlen(this->m_str)+strlen(s)+1];
strcpy(p,this->m_str);
strcat(p,s);
tempStr.m_str=p;
return tempStr;
}
CString& CString::operator =(const CString& str)
{
if (this!=&str)
{
delete[] m_str;
m_size=strlen(str.m_str);
m_str=new char[m_size+1];
strcpy(m_str,str.m_str);
}
return *this;
}
CString& CString::operator =(const char *str)
{
delete[] m_str;
m_size=strlen(str);
m_str=new char[m_size+1];
strcpy(m_str,str);
return *this;
}
int main()
{
CString s1="hello",s2("world"),s3;
s3=s1+s2;
cout<<"s3 = s1+s2 -- "<<s3.m_str<<endl;
s3=s3+"abc";
//s3="abc"+s1; //会出现什么问题?? =>会报错:no match for 'operator+' in '"abc" + s1'
cout<<"s3:"<<s3.m_str<<endl;
return 0;
}
执行结果:
s3 = s1+s2 -- helloworld
s3:helloworldabc
重载运算符‘[ ]’
实例
#include <iostream>
#include <string.h>
#include <windows.h>
using namespace std;
class CString
{
public:
CString(const char *s="");
CString(const CString& s);
char operator [](int index);
int GetSize();
char *m_str;
private:
int m_size;
};
CString::CString(const CString& s)
{
m_size=strlen(s.m_str);
m_str=new char[m_size+1];
strcpy(m_str,s.m_str);
}
CString::CString(const char *s/* ="" */)
{
m_size=strlen(s);
m_str=new char[m_size+1];
strcpy(m_str,s);
}
inline int CString::GetSize()
{
return m_size;
}
char CString:: operator [](int index)
{
if(index<0 || index>=m_size)
{//下标越界
}
return m_str[index];
}
int main()
{
CString entry("extravagant");
for(int i = 0;i<entry.GetSize();++i)
{
cout<<"entry = "<<entry[i]<<endl;
}
return 0;
}
执行结果:
entry = e
entry = x
entry = t
entry = r
entry = a
entry = v
entry = a
entry = g
entry = a
entry = n
entry = t