运算符重载

选用网课:中国大学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<

注意这里的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 
#include 
#include 
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<> 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  
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 
#include 
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

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

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

#include  
#include  
#include  
#include  
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=10)
                {
                    temps.maxNum[i]=sum%10+'0';
                    //cout<=temps.len)
                    {
                        temps.maxNum[i+1]+='0'; 
                    }
                    flag=1;
                }else{
                    //cout<<"sum:"<=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<maxNum<=i;j--)
                os<maxNum<operator +=(1);
        //cout<> 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;
}

你可能感兴趣的:(运算符重载)