大学课程学习笔记

运算符重载

2019-08-14  本文已影响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;
}
上一篇 下一篇

猜你喜欢

热点阅读