运算符重载

作者: 地球上的新新人 | 来源:发表于2019-08-14 23:52 被阅读0次

选用网课:中国大学MOOC平台,北大的程序设计与算法(三)C++面向对象程序设计
教师:郭炜
时间:2019.8.11
目标:加深对于C++中面向对象的理解

1.基本概念理解加深

-运算符重载的实质是函数的重载(;不只是狭义上的+ - * /等)
-优先重载为成员函数,在需要全局调用时,考虑友元函数
-把含运算符的表达式转换为对成员函数的调用来理解(a-b等价于a.operator+等)操作数转换为函数参数

2.赋值运算符的重载

使得赋值运算符两边类型可以不匹配,=只能重载为成员函数。为了保持一致性,=的返回值为左值的引用
如果左值正是该类,即可return *this;

注意浅复制和深复制的区别尤其是有Pointer时
eg.S1=S2,此时s1指针也指向了同一片区域,然而s1原来所指向区域成为了内存垃圾。

3.运算符重载为友元函数

我们希望,比如+,不仅可以c+5,也可以5+c

4.可变长数组的一个实例

这里注意 []的重载返回值,根据具体需求,有时是int&有时是int*

-还有一个是,要注意区分复制构造函数的浅复制坑,默认的复制构造函数只会完成成员的复制,当成员是指针时便容易发生问题

//这里的一个常规操作是,先划区域,再strcpy
//同时注意防止s=s问题
if(ptr==a.ptr)
  return *this;
else
  ptr=new int[strlen(a.ptr)+1];
  strcpy(ptr,a.ptr);

5.流插入和流输入运算符

cout是在iostream中定义的,ostream类的对象
<<本身是左移运算符,在iostream中得到了重载
对于我们的需求,需要将<<重载为全局函数,又可以访问类的私有成员,友元函数最佳。返回值仍需要为ostream对象,以满足连续输出。
eg.

friend ostream & operator<<(ostream &o, A &a){
  o<<a.num;
  return o;}

注意这里的ostream &o中,去掉&会报错,老师也没细讲原因。

6.类型转换运算符的重载

operator double(){...} 肯定无参数,无返回值类型
(int)s 等价于s.int()
在一些自定义类隐式转换中可以很好地解决问题。

7.自增自减运算符重载

为了区分++i与i++,C++规定后置运算符,需要多一个无用的int变量,以示区分。
-还有要注意的是,返回值不同。前置返回自增完的对象,后置返回自增前的备份(temp)

T & operator++()//++i
{n++;return *this;}

T operator++(int)//i++
{T tmp(*this);//备份
  n++;
  return tmp;}

几点注意

重载不改变优先级
..*::?:sizeof不能被重载
()、[]、->、=只能重载为成员函数



程序填空练习题

1.MyString

这题比较常规,关于赋值号的重载,还有个流输出重载,因为不涉及连续赋值(形如a=b=c),返回值可以设为void
但为了养成习惯,保持优雅,最好返回值设为MyString &

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class MyString {
    char * p;
public:
    MyString(const char * s) {
        if( s) {
            p = new char[strlen(s) + 1];
            strcpy(p,s);
        }
        else
            p = NULL;
    }
    ~MyString() { if(p) delete [] p; }

//begin of my code
    MyString(MyString &s){
        p=new char[strlen(s.p)+1];strcpy(p,s.p);
    }
void operator=(const char * s) {
        if(s) {
            p = new char[strlen(s) + 1];
            strcpy(p,s);
        }
        else
            p = NULL;
    }

void operator=(const MyString &s) {
        if(s.p) {
            p = new char[strlen(s.p) + 1];
            strcpy(p,s.p);
        }
        else
            p = NULL;
    }
friend ostream &operator<<(ostream &o,const MyString &s){
    o<<s.p;
    return o;
}
void Copy(const char * w){
    p=new char[strlen(w)+1];strcpy(p,w);
}
//End of my code

};
int main()
{
    char w1[200],w2[100];
    while( cin >> w1 >> w2) {
        MyString s1(w1),s2 = s1;
        MyString s3(NULL);
        s3.Copy(w1);
        cout << s1 << "," << s2 << "," << s3 << endl;
        s2 = w2;
        s3 = s2;
        s1 = s3;
        cout << s1 << "," << s2 << "," << s3 << endl;
        
    }
}

2.看上去好坑的运算符重载

这道题初次分析卡了会儿,以为是输出的n-5,n-7后来明白了Inc只是在输出时+1并没有改变,是输出n-5,n-8。
另一个点,注意到Inc()的参数是Int,而主函数中的调用时Myint型
我的初次解决方案是,在类中写了个Inc的重载函数
后来发现,可以直接写一个类型转换重载函数,重载int(),使主函数调用Inc是,隐式调用(int)可以通过。

#include <iostream> 
using namespace std;
class MyInt 
{ 
    int nVal; 
    public: 
    MyInt( int n) { nVal = n ;}
//Begin of my code
MyInt & operator-(const int &a){
nVal-=a;return *this;
}
friend int Inc(MyInt &a){
return a.nVal+1;
}
}; 
int Inc(int n) {
    return n + 1;
//End of my code
}
int main () { 
    int n;
    while(cin >>n) {
        MyInt objInt(n); 
        objInt-2-1-3; 
        cout << Inc(objInt);
        cout <<","; 
        objInt-2-1; 
        cout << Inc(objInt) << endl;
    }
    return 0;
}

上面的友元函数可以代替为

operator int()
{
  return  nVal;
}

4.二维数组类

这题卡了会儿,一开始的方案就是动态分配二维数组,但之前没有在类内存储行和列,一直卡在怎样通过动态分配的二维数组来获得行和列数。后来屈服了,在类内存储了行和列,一切自然解决了。
这里还考察了括号的重载,[]的重载。
网上关于数组存储,也可以使用静态分配的方法。那么可以用sizeof来判断行和列。

#include <iostream>
#include <cstring>
using namespace std;
class Array2 {
//Begin of my code
int **num;
int col;int row;
public:
    Array2(int a,int b):row(a),col(b){
        num=new int*[a];
        for(int i=0;i<a;++i){
            num[i]=new int[b];
        }
    }
    Array2(){num=NULL;
    } 
    Array2 &operator=(Array2 &p){   
        int l1=p.row;//行数
        int l2=p.col; 
        num=new int*[l1];
        for(int i=0;i<3;++i){
            num[i]=new int[l2]; 
            for(int j=0;j<4;++j){
                num[i][j]=p.num[i][j];
            }
        }
        return *this;
    }
    int* operator[](int &n){
        return num[n];
    }
    int operator()(int& a,int& b){
        return num[a][b];
    }
//End of my code
};
int main() {
    Array2 a(3,4);
    int i,j;
    for(  i = 0;i < 3; ++i )
        for(  j = 0; j < 4; j ++ )
            a[i][j] = i * 4 + j;
    for(  i = 0;i < 3; ++i ) {
        for(  j = 0; j < 4; j ++ ) {
            cout << a(i,j) << ",";
        }
        cout << endl;
    }
    cout << "next" << endl;
    Array2 b;     b = a;
    for(  i = 0;i < 3; ++i ) {
        for(  j = 0; j < 4; j ++ ) {
            cout << b[i][j] << ",";
        }
        cout << endl;
    }
    return 0;
}

5.别叫,这个大整数已经很简化了!

这道题乍看确实感觉挺麻烦的,需要自己做大数加法重载,判断进位等等。
参考了篇资料,将大数反向按字节存储,整型同样处理可以解决问题。

#include <iostream> 
#include <cstring> 
#include <cstdlib> 
#include <cstdio> 
using namespace std;
const int MAX = 110; 
class CHugeInt {
private:
    char maxNum[210];
    int len;
public:
    CHugeInt(char * s){
        strcpy(maxNum,s);
        int i=0,j=strlen(s)-1;
        while(i<j)
        {
            swap(maxNum[i],maxNum[j]);
            i++;
            j--;
        }
        //cout<<"init:"<<maxNum<<endl;
        len=strlen(s);
        //cout<<"Init success"<<endl;
    }
    CHugeInt(){
        len=0;
    } 
    CHugeInt(int n){
        int i=0;
        if(n==0)
        {
            maxNum[i++]='0';
        }else{
            while(n)
            {
                maxNum[i++]=n%10+'0';
                n=n/10;
            }    
        }
        maxNum[i]='\0';
        len=i;
        //cout<<maxNum<<endl;
    }
    CHugeInt  operator+(CHugeInt & a)
    {
            //cout<<"hrer"<<endl;
            int i=0,j=0;
            int t,sum=0;
            CHugeInt temps;
            strcpy(temps.maxNum,maxNum);
            temps.len=len;
            //cout<<"before:"<<temps.maxNum<<endl;
            //maxNum=new char[strlen(a.maxNum)+1];
            //cout<<a.len<<","<<len<<endl;
            int flag=0;
            while(j<a.len&&i<temps.len)
            {
                t=a.maxNum[j]-'0';
                int te=temps.maxNum[i]-'0';
                sum=t+te;
                //cout<<t<<"+"<<te<<":"<<sum<<endl;
                if(sum>=10)
                {
                    temps.maxNum[i]=sum%10+'0';
                    //cout<<temps.maxNum[i]<<endl;
                    temps.maxNum[i+1]=sum/10+temps.maxNum[i+1];
                    if(i+1>=temps.len)
                    {
                        temps.maxNum[i+1]+='0'; 
                    }
                    flag=1;
                }else{
                    //cout<<"sum:"<<sum<<endl;
                    flag=0;
                    temps.maxNum[i]=sum+'0';
                }
                //cout<<temps.maxNum[i]<<endl;
                i++,j++;
                sum=0;
            }
            while(j<a.len)
            {
                if(flag==1)
                {
                    temps.maxNum[i+1]=a.maxNum[j];
                    i++,j++;    
                }else{
                    temps.maxNum[i]=a.maxNum[j];
                    i++,j++;
                }
            }
            if(i>=len)
            {
                if(flag==1){
                    temps.maxNum[i+1]='\0';
                    temps.len=i+1;
                }
                else{
                    temps.maxNum[i]='\0';
                    temps.len=i;
                }        
            }
        return temps;
    }
    /*operator char *()
    {
        return maxNum;
    }*/
    CHugeInt & operator +=(int n)
    {
        CHugeInt temps(n);
        *this=this->operator+(temps);
        //cout<<this->maxNum<<endl;
        return *this;
    }
    friend ostream & operator<<(ostream & os,const CHugeInt & s)
    {
            int i=0,j=s.len-1;
            //cout<<"len:"<<s.len<<endl;
            //cout<<"输出:"<<s.maxNum<<endl;
            for(;j>=i;j--)
                os<<s.maxNum[j];
            return os;
    }
    friend CHugeInt  operator+(int n,CHugeInt  s)
    {
        CHugeInt temps(n);
        s=s+temps;
        return s;
    }
    friend CHugeInt  operator+(CHugeInt  s,int n)
    {
        CHugeInt temps(n);
        s=s+temps;
        return s;
    }
    CHugeInt &  operator++()
    {
        (*this)+=1;
        //cout<<"前置自增后:"<<this->maxNum<<endl;
        return *(this);
    }
    CHugeInt   operator++(int n)
    {
        CHugeInt temps;
        strcpy(temps.maxNum,maxNum);
        temps.len=len;
        this->operator +=(1);
        //cout<<temps.maxNum<<endl;
        //cout<<"len:"<<temps.len<<endl;
        return temps;
    }
 
};
int  main() 
{ 
    char s[210];
    int n;
 
    while (cin >> s >> n) {
        CHugeInt a(s);
        CHugeInt b(n);
 
        cout << a + b << endl;
        cout << n + a << endl;
        cout << a + n << endl;
        b += n;
        cout  << ++ b << endl;
        cout << b++ << endl;
        cout << b << endl;
    }
    return 0;
}

相关文章

  • 运算符重载及其他约定

    7.1 重载算术运算符 重载二元算术运算符 重载复合赋值运算符 重载一元运算符 重载比较运算符 等号运算符:‘eq...

  • C++ 部分运算符重载

    可重载的运算符 不可重载的运算符和符号 重载运算符为类的成员函数 重载运算符为友元函数 重载赋值运算符 重载流插入...

  • 2019-07-11 运算符的重载

    运算符的重载 重载运算符 (“::”,“.*”,“.”,“?:”)不能被重载。 重载运算符时,不能改变其本质,如不...

  • 运算符重载

    一.+号运算符重载 二.<<号运算符重载 三.指针运算符重载(智能指针)

  • C++运算符重载-下篇 (Boolan)

    C++运算符重载-下篇 (Boolan) 本章内容:1. 运算符重载的概述2. 重载算术运算符3. 重载按位运算符...

  • C++运算符重载-上篇 (Boolan)

    C++运算符重载-上篇 (Boolan) 本章内容:1. 运算符重载的概述2. 重载算术运算符3. 重载按位运算符...

  • C++重载

    重载 C++语言规定: 重载的运算符要保持原运算符的意义。只能对已有的运算符重载,不能增加新的运算符。重载的运算符...

  • C++运算符重载详解

    运算符重载规则 1.被重载的运算符必须是已经存在的C++运算符,不能重载自己创建的运算符; 2.运算符被重载之后,...

  • 第十一章 使用类

    运算符重载 运算符重载是一种形式的C++多态。运算符重载将重载的概念扩展到运算符上,允许赋予C++运算符多种含义。...

  • 4.0 C++远征:重载运算符

    重载运算符 [TOC] 四、重载运算符 ​ 概念 : 给原有运算符赋予新功能。 ​ 本质 : 函数重载。 ...

网友评论

    本文标题:运算符重载

    本文链接:https://www.haomeiwen.com/subject/ayyejctx.html