4.1运算符重载
- 对已有的运算符赋予多重的含义
- 使同一运算符作用于不同类型的数据时能够有不同的功能
- 扩展c++中运算符的功能
5+4=9
5+6i+7+3i=12+9i - 运算符重载的实质是函数的重载
返回值类型 operator 运算符(形参表){…}
class complex{
public:
complex(int a,int b){real=a;imag=b;}
int real,imag;
complex operator+(const complex& a){
return complex(real+a.real,imag+a.imag)
}//重载为成员函数的时候只需要一个参量。
};
complex::complex operator+(const complex &a,const complex &b){
return complex(a.real+b.real,a.imag+b.imag)
}//重载为普通函数的时候为两个参量,为运算符目数。两者是等价的
4.2赋值运算符 = 的重载
- 可以将赋值运算符重载为想要的功能,比如把int赋值给complex等。
- 赋值运算符 = 只能重载为成员函数
e.g 自己的string类
#include <iostream>
using namespace std;
class String{
private:
char *str;
public:
String():str(NULL){}
const char *c_str(){return str;}
char *operator =(const char *s);
~String();
String(const char *s1){
str=new char[strlen(s1)+1];
strcpy(str,s1);//用*char可以完成,strcpy做的是拷贝的工作,将后者拷贝给前者
}
};
char *String::operator=(const char *s){
if(str) delete[] str;
if(s){
str=new char[strlen(s)+1];
strcpy(str,s);
}else{
str=NULL;
}
return str;
}
String::~String(){
if(str) delete[] str;
}
int main(){
String s;
s="good sdf";//为了满足这个等号,需要对赋值运算符进行重载
String s2="hello lsidfh";
cout<<s.c_str()<<endl;//s.c_str()目的是返回一个*char
cout<<s2.c_str()<<endl;
return 0;
}
深拷贝和浅拷贝
- 当自己不定义复制构造函数的时候,系统会自动生成一个复制构造函数,将原有的内容一字节一字节的拷贝给新的对象。
- 但有时候,我们并不希望如此,当对象的成员变量有指针的时候,会出现以下情况:a对象和b对象的指针内容在相同的内存空间中,则可以通过b对象的成员指针改变a对象的内容,这不是我们想要的
- 于是有了深拷贝,需要对新对象的指针对象开辟新的空间,并复制原来对象的内容进去,这样,虽然先后两个对象的指针变量指的内容是一致的,但在内存空间中是不同的位置,不会相互影响
4.3运算符重载为友元函数
- 成员函数不能满足使用需求,而普通函数不能访问类私有成员
例如,现有一个类名叫complex,要实现complex+5,可以通过成员函数的重载实现,这句话等于complex.+(5),但若想要实现5+complex,需要对整体的 + 进行重载,就不能是成员函数,而是要普通函数,而普通函数不能访问类的私有成员,所以只能是友元函数才可以。
class complex{
private:
double real,imag;
public:
complex(double r, double i):real(r),imag(i){};
complex operator+ (double r){
return complex(real+r,imag);
}//对于后置的加号,只要通过成员函数即可实现
};
int main(){
complex a(2,3),b(1,1);
b=a+5;//完成后置加号的重载
return 0;
}
对于前置加号,只能通过重载为友元实现
class complex{
private:
double real,imag;
public:
complex(double r, double i):real(r),imag(i){};
complex operator+ (double r){
return complex(real+r,imag);
}
friend complex operator+ (double r,const complex& c);//申明友元函数
};
complex operator+ (double r,const complex& c){
return complex(c.real+r,c.imag);
}//定义普通函数operator+
int main(){
complex a(2,3),b(1,1);
b=a+5;
b=5+a;
return 0;
}
4.4 e.g.可变长整形数组
- 需求,编写一个程序,完成动态可变数组,需要多大的数组,就可以扩大成为那么大的。
需要实现的c++主程序:
int main(){
CArray a;//创建一个可变数组对象
for(int i=0;i<5;++i){
a.push_back(i);//支持push_back函数加入新的元素
}
CArray a2,a3;
a2=a;//可以通过等号进行深拷贝
for(int i=0;i<a.length();++i){
cout<<a2[i]<<" ";//支持流输出运算符
}
a2=a3;
for(int i=0;i<a2.length();++i){
cout<<a2[i]<<" ";
}
cout<<endl;
a[3]=100;//支持直接调用
CArray a4(a);//支持这样构造
for(int i=0;i<a4.length();++i){
cout<<a4[i]<<" ";
}
return 0;
}
实现:
#include <iostream>
using namespace std;
class CArray{
public:
int *a1;
int size;
void push_back(const int &a){//将新的地址加上新的元素赋值给旧的
int *p2;
int *p1;
int *a3;
a3=a1;
p1=new int[size+1];
p2=p1;
for(int i=0;i<size;++i){
*p2=*a3;
++p2;
++a3;
}
*p2=a;
++size;
a1=p1;
delete p1;
}
CArray (CArray &a){//深拷贝
size=a.size;
int *p1;
int *p2;
p1=new int[size];
p2=p1;
for(int i=0;i<size;++i){
*p2=*(a.a1+i);
++p2;
}
a1=p1;
delete [] p1;
}
CArray(){size=0;}
int length(){return size;}
int & operator[](int i){//实现[]调用
return a1[i];
}
~CArray(){//检查是否还有未删除的指针
if(a1){delete [] a1;}
}
};
int main(){
CArray a;
for(int i=0;i<5;++i){
a.push_back(i);
}
CArray a2,a3;
a2=a;
for(int i=0;i<a.length();++i){
cout<<a2[i]<<" ";
}
a2=a3;
for(int i=0;i<a2.length();++i){
cout<<a2[i]<<" ";
}
cout<<endl;
a[3]=100;
CArray a4(a);
for(int i=0;i<a4.length();++i){
cout<<a4[i]<<" ";
}
return 0;
}
4.5流插入运算符和流提取运算符的重载
- 若想输出或者输入某个类,就要对其进行重载,重载为ostream/istream的引用
e.g.
假设c是complex复数类的对象,现在希望写 “cout<
#include <iostream>
using namespace std;
class Complex{
private:
double real,imag;
public:
Complex(int a=0,int b=0):real(a),imag(b){}
friend ostream &operator<<(ostream & o,const Complex &s);
friend istream &operator>>(istream & o,Complex &s);//申明友元的重载
};
ostream &operator<<(ostream & o,const Complex &s){
o<<s.real<<"+"<<s.imag<<"i";
return o;
}
istream &operator>>(istream & o,Complex &c){
string s;
o>>s;
int pos=s.find("+",0);
string stmp=s.substr(0,pos);
c.real=atof(stmp.c_str());
stmp=s.substr(pos+1,s.length()-pos-2);
c.imag=atof(stmp.c_str());
return o;
}
int main(){
Complex c;
int n;
cin>>c>>n;
cout<<c<<","<<n;
return 0;
}
4.6自加/自减运算符的重载
- 自加自减运算符分前置后置分别进行重载
- 前置运算符作为一元运算符重载
重载为成员函数时,变量减一
- T operator++();
- T operator–();
重载为全局函数,变量为一
- T operator++(T);
- T operator–(T);
后置运算符作为二元运算符重载
- 重载为成员函数时候,变量减一,多写一个参数,具体无意义
- T operator++(int)
- T operator–(int)
- 重载为全局函数的时候,有两个变量
- T operator++(T, int)
- T operator–(T, int)
#include <iostream>
using namespace std;
class cdemo{
private:
int a;
public:
friend ostream &operator<<(ostream &o,cdemo &s);
cdemo(int i):a(i){}
cdemo &operator ++(){//前置,不需要加变量
a++;
return *this;
}
cdemo &operator ++(int){//后置,需要加个变量
cdemo tmp(*this);
a++;
return tmp;
}
};
ostream &operator<<(ostream &o,cdemo &s){//流输出重载
o<<s.a;
return o;
}
int main(){
cdemo d(5);
cout<<(d++)<<",";
cout<<d<<",",
cout<<(++d)<<",";
cout<<d<<endl;
cout<<(d--)<<","
cout<<d<<",";
cout<<(--d)<<","
cout<<d<<",";
cout<<d<<endl;
return 0;
}