c中运算符种类(中的运算符重载)
c中运算符种类(中的运算符重载)3、函数体:2.2:函数结束前返回实例自身的引用,既*this。1.2:考虑到修饰的形参不能被修改且要能接收隐式产生的临时量,我们要传常引用。2、返回值:2.1:考虑到要能进行连续赋值,我们要传引用,因为如果不传引用的话,传回去第二次赋的值就给了临时量,而且表达式结束时临时量被销毁,不能做到连续赋值。
我们在刚开始学面向对象时就了解了C 中的六个默认构造函数,其中有一个就是赋值运算符重载函数,它重载的是赋值运算符,今天我们就对赋值运算符重载函数具体的要求和写法做以总结。其次再举例说明其他的重载函数。
当我们给出一个类的声明时,写赋值运算符函数要考虑三个方面:
1、传参:
1.1:对于操作运算符重载函数要传的参数可以是引用也可以不是引用。但考虑到传引用时不用生成一个临时对象,不用调用拷贝构造函数,效率高,我们选择传引用。
1.2:考虑到修饰的形参不能被修改且要能接收隐式产生的临时量,我们要传常引用。
2、返回值:
2.1:考虑到要能进行连续赋值,我们要传引用,因为如果不传引用的话,传回去第二次赋的值就给了临时量,而且表达式结束时临时量被销毁,不能做到连续赋值。
2.2:函数结束前返回实例自身的引用,既*this。
3、函数体:
3.1:判断自赋值,如果自赋值,直接返回。
3.2:释放自身的资源,防止内存泄漏。
3.3:开辟新的资源,防止同一块内存区域被释放多次,导致程序奔溃。
对于运算符的操作数,编译器只能识别基础的数据类型,如果要使用符合的数据类型(如结构体),则需要对运算符的操作数进行拓展是运算符支持复合数据类型,C 中的运算符重载就解决了这一问题。
运算符函数定义的一般格式如下:
数据类型 operator<运算符符号>(参数列表)
{
<函数体>
}
有一些特殊的运算符不能被重载:域解析符(::),条件运算符(?:),直接成员访问运算符(.),类成员指针引用运算符(.*) sizeof运算符(sizeof)
运算符重载分为类的内部方式和全局方式,同一种运算符,全局和内部方式只能存在一种。当无法修改左操作数的类时,使用全局函数进行重载。
eg:计算虚数
class Complex
{
friend Complex operator (Complex &c1 Complex &c2);
//使用到类的私有变量,需要设为友元函数
friend Complex operator (Complex &c1 int num);
public:
Complex(int a = 0 int b = 0)
{
this->a = a;
this->b = b;
}
void show()
{
printf("%d %di\n" a b);
}
Complex add(Complex &c)//Complex add(Complex*const this Complex &c)
{
Complex tmp(a c.a b c.b);
return tmp;
}
Complex operator-(Complex &c)//Complex operator-(Complex*const this Complex &c)
{
Complex tmp(a-c.a b-c.b);
return tmp;
}
private:
int a;//实部
int b;//虚部
};
//全局方式:加法运算符的重载:对象 对象
Complex operator (Complex &c1 Complex &c2)
{
Complex tmp(c1.a c2.a c1.b c2.b);
return tmp;
}
//全局方式:加法运算符的重载:对象 常量
Complex operator (Complex &c1 int num)
{
Complex tmp(c1.a num c1.b);
return tmp;
}
//全局方式:全局函数重载运算符
int main()
{
Complex c1(1 2) c2(3 4) c3;
cout << "c1 = 1 2i; c2 = 3 4i" << endl;
cout << "全局方式" << endl;
//编译器不知道如何运算自定义类型,所以不允许直接进行运算
//需要自己写运算规则,写执行函数
// 1.编译器发现c1和c2是自定义类型
// 2.它们要进行 运算
// 3.调用函数执行相应的功能: operator (c1,c2)
// 4.如果存在operator (c1,c2)则执行成功,如果不存在则报错
c3 = c1 c2; // operator (c1,c2) 对象 对象
cout << "operator (c1,c2):";
c3.show();
c3 = c1 10; // operator (c1 10) 对象 常量
cout << "operator (c1 10):";
c3.show();
return 0;
}
//内部方式:类的内部成员(函数)
int main()
{
Complex c1(1 2) c2(3 4) c3;
cout << "c1 = 1 2i; c2 = 3 4i" << endl;
cout << "内部方式" << endl;
c3 = c1.add(c2);/* add省略参数c1,因为调用的是c1中的add函数,
对象c1中有this指针可提供c1的地址,
等价于 add(&c1 c2) =====>c1 c2*/
c3 = c2.add(c1);//add(&c2 c1)=====>c2 c1 参数顺序要清楚,在- * /运算时会影响结果
cout << "c3 = c1 - c2" << endl;
c3 = c1 - c2; // c1.operator-(c2) =====> operator-(&c1 c2)
cout << "operator-(&c1 c2):";
c3.show();
cout << "c3 = c2 - c1" << endl;
c3 = c2 - c1; // c2.operator-(c1) =====> operator-(&c2 c1)
cout << "operator-(&c2 c1):";
c3.show();
return 0;
}
运算符重载是类的友元函数是
调用格式:friend <返回类型> operator<运算符>(参数表)
在类外定义:《返回类型》 operator<运算符》(参数表)
友元函数可以调用类的私有成员,相当于类的公有成员
显示的调用:operator (a b)
#include<iostream>
using namespace std;
class A
{
private:
int a b;
public:
A(int x = 0 int y = 0)
{
a = x;
b = y;
}
int geta()
{
return a;
}
int getb()
{
return b;
}
friend A operator (A p A q);
};
A operator (A p A q)
{
A temp;
temp.a = p.a q.a;
temp.b = p.b q.b;
return temp;
}
int main()
{
A ob1(1 2) ob2(3 4) ob3 ob4;
ob3 = ob1 ob2;
ob4 = operator (ob1 ob2);
cout << ob3.geta() << " " << ob3.getb() << endl;
cout << ob4.geta() << " " << ob4.getb() << endl;
system("pause");
return 0;
}
有了以上的掌握,接下来借助一个类CString我们书写 [] == != << >>运算符重载函数
#include<iostream>
#include<string>
using namespace std;
class CString
{
public:
CString()
{
cout<<"CString()"<<endl;
mpstring=new char[1];
cursize=0;
}
CString(char* str)
{
cout<<"CString(char*)"<<endl;
mpstring=new char[strlen(str) 1];
strcpy(mpstring str);
cursize=strlen(str);
}
~CString()
{
cout<<"~CString()"<<endl;
delete[] mpstring;
mpstring=NULL;
}
CString& operator=(const CString& rhs)
{
cout<<"operator="<<endl;
/*
if(this == &rhs)
{
return *this;
}
delete[] mpstring;
mpstring=new char[strlen(rhs.mpstring) 1];
strcpy(mpstring rhs.mpstring);
cursize=rhs.cursize;
return *this;*/
if(this!=&rhs)
{
delete[] mpstring;
mpstring=new char[strlen(rhs.mpstring) 1];
strcpy(mpstring rhs.mpstring);
cursize=rhs.cursize;
}
return *this;
}
bool operator==(const CString& rhs)
{
cout<<"operator=="<<endl;
return strcmp(mpstring rhs.mpstring)==0;
}
bool operator!=(const CString& rhs)
{
cout<<"operator!="<<endl;
//return strcmp(mpstring rhs.mpstring)!=0;//方法一
return !(*this==rhs);//方法二
}
char& operator[](int index)
{
cout<<"operator[]"<<endl;
return mpstring[index];
}
private:
char* mpstring;
int cursize;
friend CString operator (const CString& const CString&);
friend ostream& operator<<(ostream& const CString&);
friend istream& operator>>(istream& CString&);
};
CString operator (const CString& lhs const CString& rhs)
/*必须写在类外,因为要满足所有情况,
比如:CString str3=str1 "world";或者CString str4="Hello" str1;*/
{
cout<<"operator "<<endl;
int lhs_len=strlen(lhs.mpstring);
int rhs_len=strlen(rhs.mpstring);
int len=lhs_len rhs_len 1;
//char* str=new char[len];
char str[20]="";
strcat(str rhs.mpstring);
strcat(str rhs.mpstring);
//CString obj(str);
return CString(str);
}
ostream& operator<<(ostream& out const CString& rhs)
{
cout<<"operator<<"<<endl;
out<<rhs.mpstring<<"";
return out;
}
istream& operator>>(istream& in CString& rhs)//输入流要修改,所以不用加const
{
cout<<"operator>>"<<endl;
char p[20];
in>>p;
if(in)
{
delete[] rhs.mpstring;
rhs.mpstring=new char[strlen(p) 1];
strcpy(rhs.mpstring p);
rhs.cursize=strlen(p);
}
return in;
}
int main()
{
CString str1;
CString str2("hello");
CString str3=str2 "world";
CString str4="hello" str2;
str3=str4;
if(str2!=str4)
{
cout<<str4<<endl;
}
if(str3==str4)
{
cout<<str3<<endl;
cout<<str3[0]<<endl;
}
cin>>str1;
cout<<str1<<endl;
return 0;
}
运行结果: