C++关于运算符重载

1、运算符重载,就是对已有的运算符赋予多重含义,使同一运算符作用于不同类型的数据时产生不同的行为。运算符重载的目的是使得C++中的运算符能用来操作对象。

2、运算符重载的实质是编写以运算符作为名称的函数。

```c++

//运算符函数的格式

返回值类型 operator 运算符(形参表)

{

    //...

}

```

3、包含被重载的运算符的表达式会被编译成对运算符函数的调用,运算符的操作数成为函数调用时的实参,运算的结果就是函数的返回值。运算符可以被多次重载。运算符可以被重载为全局函数,也可以被重载为成员函数。一般来说,倾向于将运算符重载为成员函数,这样能较好地体现运算符和类之间的关系。

```c++

#include<iostream>

using namespace std;

class Complex{

    public:

        double real,imag;

        Complex(double r=0.0,double i=0.0):real(r),imag(i){

        }

        Complex operator - (const Complex& c);

};

Complex operator + (const Complex& a,const Complex& b){

    return Complex(a.real+b.real,a.imag+b.imag);

}

Complex Complex::operator -(const Complex& c){

    return Complex(real-c.real,imag-c.imag);

}

int main(){

    Complex a(4,4),b(1,1),c;

    c = a + b;

    cout<<c.real<<","<<c.imag<<endl;

    cout<<(a-b).real<<","<<(a-b).imag<<endl;

    return 0;

}

//输出结果

/*

5,5

3,3

*/

```

4、C++规定,“=”只能重载为成员函数。

5、同类对象之间可以通过赋值运算符“=”互相赋值。如果没有经过重载,“=”的作用就是把左边的对象的每个成员变量都变得和右边的对象相等,即执行逐个字节拷贝的工作,这种拷贝叫做“浅拷贝”。

6、经过重载,赋值号“=”的功能不再是浅拷贝,而是将一个对象中指针成员变量指向的内容复制到另一个对象中指针成员变量指向的地方。这样的拷贝就叫“深拷贝”。

7、实例:长度可变的整型数组类。

特点:

(1)数组的元素个数可以在初始化该对象时指定。

(2)可以动态往数组中添加元素。

(3)使用该类时不用担心动态内存分配和释放的问题。

(4)能够像使用数组那样使用动态数组类对象,如可以通过下标访问其元素。

```c++

#include<iostream>

#include<cstring>

using namespace std;

class CArray{

    int size;   //数组元素个数

    int* ptr;   //指向动态分配的数组

    public:

        CArray(int s=0);    //实现特点(1),此处声明时写了函数参数的默认值,则在定义时不能再写

        CArray(const CArray& a);    //拷贝构造函数,实现特点(3)的动态内存分配,深拷贝

        ~CArray();                  //析构函数,实现特点(3)的动态内存释放

        void push_back(int v);      //实现特点(2)

        CArray& operator = (const CArray& a);   //使“=”左边对象中存放的数组的大小和内容都与右边的对象一样

        int length()const{      

            return size;

        }

        int& operator [](int i){    //实现特点(4),函数返回值为int引用才能使得a[i]能作为左值

            return ptr[i];

        }

};

CArray::CArray(int s):size(s){          

    if(s==0)

        ptr = NULL;

    else

        ptr = new int[s];  

}

CArray::CArray(const CArray& a){

    if(!a.ptr){             //如果对象a.ptr是空指针

        ptr = NULL;

        size = 0;

        return;

    }                      

    ptr = new int[a.size];  //深拷贝

    memcpy(ptr,a.ptr,sizeof(int)*a.size);   //按字节复制函数

    size = a.size;

}

CArray::~CArray(){

    if(ptr)             //注意在释放前判断ptr是否为空指针

        delete[] ptr;

}

CArray& CArray::operator =(const CArray& a){

    if(ptr==a.ptr)          //防止a = a这样的赋值导致错误

        return *this;

    if(a.ptr==NULL){    //如果a里面的数组是空的

        if(ptr)

            delete[] ptr;

        ptr = NULL;

        size = 0;

        return *this;

    }

    if(size<a.size){    //如果原有空间不够大,需要重新分配新的空间

        if(ptr)

            delete[] ptr;

        ptr = new int[a.size];

    }

    memcpy(ptr,a.ptr,sizeof(int)*a.size);

    size = a.size;

    return *this;

}

void CArray::push_back(int v){      //在数组尾部添加一个元素

    if(ptr){        

        int* tmpPtr = new int[size+1];//重新分配空间

        memcpy(tmpPtr,ptr,sizeof(int)*size);//复制原数组内容

        delete[] ptr;

        ptr = tmpPtr;

    }

    else //数组本来为空

        ptr = new int[1];

    ptr[size++] = v;

}

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;    //a2为空

    for(int i=0;i<a2.length();++i)  //a2.length()返回0

        cout<<a2[i]<<" ";

    cout<<endl;

    a[3] = 100;

    CArray a4(a);

    for(int i=0;i<a4.length();++i)

        cout<<a4[i]<<" ";

    return 0;

}

//输出结果:

/*

0 1 2 3 4

0 1 2 100 4

*/

```

8、假定c是Complex复数类的对象,现在希望写“cout << c;”就能以a+bi的形式输出c的值;写“cin>>c;”就能从键盘接受a+bi形式的输入,并且使得c.real = a,c.imag = b。显然,要对“>>”和“<<”进行重载。

```c++

#include<iostream>

#include<string>

#include<cstdlib>

using namespace std;

class Complex{

    double real,imag;

    public:

        Complex(double r=0,double i=0):real(r),imag(i){

        }

        friend ostream& operator<<(ostream& os,const Complex& c);

        friend istream& operator>>(istream& is,Complex& c);

};

ostream& operator<<(ostream& os,const Complex& c){

    os<<c.real<<"+"<<c.imag<<"i";

    return os;

}

istream& operator>>(istream& is,Complex& c){

    string s;

    is>>s;

    int pos=s.find("+",0);

    string sTmp=s.substr(0,pos);

    c.real=atof(sTmp.c_str());      //float atof(const char*),在cstdlib头文件中声明,将字符串转换为浮点数。

    sTmp=s.substr(pos+1,s.length()-pos-2);

    c.imag = atof(sTmp.c_str());

    return is;

}

int main(){

    Complex c;

    int n;

    cin>>c>>n;

    cout<<c<<","<<n;

    return 0;

}

//输入:13.2+133i 87

//输出:13.2+133i,87

/*因为没办法修改ostream和istream类,所以只能将“<<”和“>>”重载为全局函数的形式。

由于这两个函数需要访问Complex类的私有成员,因此在Complex类定义中将它们声明为友元。

全局函数的返回值和参数必须加上&,因为ostream和istream的复制构造函数是私有的,没有办法生成ostream和istream对象。

*/

```

9、在C++中,类型的名字(包括类的名字)本身也是一种运算符,即类型强制转换运算。类型强制转换运算符是单目运算符,也可以被重载,但只能重载为成员函数,不能重载为全局函数。重载强制类型转换运算符时,不需要指定返回值类型,因为返回值类型是确定的,就是运算符本身代表的类型。

```c++

#include<iostream>

using namespace std;

class Complex{

    double real,imag;

    public:

        Complex(double r=0,double i=0):real(r),imag(i){

        }

        operator double(){  

            return real;

        }

};

int main(){

    Complex c(1.2,3.4);

    cout<<(double)c<<endl;      //等价于c.operator double()

    double n = 2 + c;           //等价于double n = 2 + c.operator double();

    cout<<n;

    return 0;

}

//输出结果:

/*

1.2

3.2

*/

```

10、C++规定,在重载“++”或“--”时,允许写一个增加了无用int类型形参的版本,编译器处理“++”或“--”前置的表达式时,调用参数个数正常的重载函数;处理后置表达式时,调用多出一个参数的重载函数。

```c++

#include<iostream>

using namespace std;

class CDemo{

    private:

        int n;

    public:

        CDemo(int i=0):n(i){

        }

        CDemo& operator ++();

        CDemo operator ++(int);

        operator int(){

            return n;

        }

        friend CDemo& operator --(CDemo& );

        friend CDemo operator --(CDemo& ,int);

};

CDemo& CDemo::operator ++(){

    n++;

    return *this;

}

CDemo CDemo::operator ++(int k){        //编译器自动以0作为实参

    CDemo tmp(*this);

    n++;

    return tmp;

}

CDemo& operator --(CDemo& d){

    d.n--;

    return d;

}

CDemo operator --(CDemo& d,int k){      //编译器自动以0作为实参

    CDemo tmp(d);

    d.n--;

    return tmp;

}

int main(){

    CDemo d(5);

    cout<<(d++)<<",";//同时注意d类型被强制转换为了d.n

    cout<<d<<",";

    cout<<(++d)<<",";

    cout<<d<<endl;

    cout<<(d--)<<",";

    cout<<d<<",";

    cout<<(--d)<<",";

    cout<<d<<endl;

    return 0;

}

//输出结果:

/*

5,6,7,7

7,6,5,5

*/

```

11、C++规定,运算符重载不改变运算符的优先级。重载运算符时,应尽量保留运算符原本的特性。

12、以下运算符不能被重载:“.”、“.*”、“::”、“?:”、sizeof。

13、重载运算符“()”、“[]”、“->”或者赋值运算符“=”时,只能将它们重载为成员函数,不能重载为全局函数。

14、“<<”和“>>”是在iostream中被重载,才成为所谓的“流插入运算符”和“流提取运算符”的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值