• Coursera课程笔记----C++程序设计----Week4


    运算符重载(week 4)

    运算符重载-基本概念

    运算符

    • C++预定义表示对数据的运算
      • +,-,*,/.....
      • 只能用于基本的数据类型
        • 整形,实型,字符型,逻辑型等
    • C++提供了数据抽象的手段➡️用户自己定义数据类型--
      • 调用类的成员函数,操作它的对象
    • 类的成员函数操作对象时,有时候会很不方便
      • 在数学上,两个复数可以直接进行+/-等
      • 在C++中,直接将+和-用于复数是不允许的

    运算符重载

    • 抽象数据类型也能够直接使用C++提供的运算符

      • 程序更简洁
      • 代码更容易理解
    • 举例:

      • complex_a和complex_b两个复数对象
      • 求两个复数的和,希望能直接写成:complex_a +
    • 对已有运算符赋予多重的含义

      • 使同一运算符作用于不同类型的数据时,产生不同的行为
    • 目的是扩展C++中提供的运算符的适用范围,以用于类所表示的抽象数据类型

    • 实质是函数重载

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

      {

      ......

      }

    • 在程序编译时

      • 把含运算符的表达式,当作对运算符函数的调用
      • 把运算符的操作数,当作运算符函数的参数
      • 运算符多次被重载时,根据实参的类型决定调用哪个运算符函数
      • 运算符可以被重载为普通函数,也可以被重载为类的成员函数
      • 重载为普通函数时,参数个数为运算符目数
      • 重载为成员函数时,参数个数为运算符目数-1
    class Complex{
      public:
      	Complex(double r = 0.0, double i = 0.0)
        {
          real = r;
          imaginary = i;
        }
      double real; //real part
      double imaginary; //imaginary part
    };
    
    Complex operator+ (const Complex &a,const Complex &b)
    {
      return Complex(a.real+b.real,a.imaginary+b.imaginary);
    } //“类名(参数表)”就代表一个对象
    
    Complex a(1,2),b(2,3),c;
    c = a + b;
    
    class Complex{
      public:
      	Complex(double r =0.0,double m = 0.0):
      					real(r),imaginary(m){}
      	Complex operator+ (const Complex &);
      	Complex operator-(const Complex &);
    }
    
    Complex Complex::operator+(const Complex & operand2){
      return Complex(real + operand2.real,
                    imaginary + operand2.imaginary);
    }
    Complex Complex::operator-(const Complex & operand2){
      return Complex(real - operand2.real,
                    imaginary - operand2.imaginary);
    }
    int main(){
      Complex x,y(4.3,8.2),z(3.3,1,1);
      x = y + z;
      x = y - z;
      return 0;
    }
    

    赋值运算符的重载

    赋值运算符‘=’重载

    • 赋值运算符两边类型可以不匹配
      • 把一个int类型变量赋值给一个Complex对象
      • 把一个char* 类型的字符串赋值给一个字符串对象
    • 需要重载赋值运算符‘=’
      • 只能重载为成员函数
    • 例:编写一个长度可变的字符串类String
      • 包含一个char *类型的成员变量,指向动态分配的存储空间
    • 该存储空间用于存放''结尾的字符串
    class String{
      private:
      	char* str;
      public:
      	String():str(NULL){ }//构造函数,初始化str为NULL
      	const char* c_str() {return str;}
      	char* operator = (const char* s);
      ~String();
    }
    
    //重载'='->obj="hello"能够成立
    char *String::operator = (const char* s)
    {
      if(str) delete[] str;
      if(s){ //s不为空时才执行拷贝
        str = new char[strlen[s]+1];
        strcpy(str,s);
      }
      else
        str = NULL;
      return str;
    };
    
    String::~String(){
      if(str) delete [] str;
    };
    
    
    int main(){
      String s;
      s = "Good Luck,";
      cout<<s.c_str()<<endl;
      //String s2 = "hello!"; 此条语句不注释掉会报错
      //因为这句是初始化语句而不是赋值语句,所以不会调用=的重载函数
      s = "Shenzhou 8!";
      cout<<s.c_str()<<endl;
      return 0;
    }
    

    重载赋值运算符的意义——浅复制和深复制

    • S1 = S2;

    • 浅复制/浅拷贝(如果不进行重构,系统会系统生成一个缺省的,会发生浅拷贝现象)

      • 执行逐个字节的复制工作
      • 会产生内存垃圾or内存错误
    • 深复制/深拷贝

      • 将一个对象中指针变量指向的内容,复制到另一个对象中指针成员对象所指的对象

      • 如何实现:在class String里添加成员函数

      • 在成员变量中包含指针的情况下,都应该主动重载赋值运算符和复制构造函数。

        //使S1=S2不再是浅拷贝而是深拷贝
        String & operator = (const String & s){
          if(str) delete[] str;
          str = new char[strlen(s.str)+1];
          strcpy(str,s.str);
          return *this;
        }
        
      • 自身给自身赋值时,该怎么处理?

        *添加一句:if(str == s.str) return this

    对operator = 返回值类型的讨论

    • void 好不好?
      • NO.考虑a = b = c
    • String 好不好?(而不是String &)
      • 可以是可以,但是不好
      • 运算符重载时,要求一个好的风格,尽量保留运算符原本的特性
      • 考虑:(a=b)=c; //会修改a的值
      • 分别等价于:(a.operator=(b)).operator(c); 在该式中,只有(a=b)返回的对象类型为引用时,才能顺利成为下一个operator函数作用的对象,进行进一步赋值的工作

    以上String类的问题

    • 为String类编写复制构造函数时,会面临和赋值运算符‘=’同样的问题(浅拷贝or深拷贝),也用同样的方法去处理

      String::String(String &s)
      {
        if(s.str){
          str = new char[strlen(s.str)+1];
          strcpy(str,s.str);
        }
        else
          str = NULL;
      }
      

    运算符重载外友元函数

    • 通常,将运算符重载为类的成员函数
    • 重载为友元函数的情况:
      • 成员函数不能满足使用要求
      • 普通函数,不能访问类的私有成员
    class Complex{
      	double real,imag;
      public:
      	Complex(double r, double i):real(r),imag(i){ };
      	Complex operator+(double r)
    };
    Complex Complex::operator+(double r){//能解释c+5
      return Complex(real + r, imag);
    }
    
    • 经过上述重载后:
    int main()
    {
      Complex c; 
      c = c + 5;//有定义,相当于c = c.operator + (5);
      c = 5 + c;//编译出错
    }
    
    • 为了使上述表达式能成立,需要将+重载为普通函数
    Complex operator+(double r, const Complex & c){
      return Complex(c.real+r,c.imag)
    }
    
    • 但普通函数不能访问私有成员,因此只能将运算符+重载为友元函数
    class Complex{
      	double real,imag;
      public:
      	Complex(double r, double i):real(r),imag(i){ };
      	Complex operator+(double r)
          friend Complex operator+(double r, const Complex & c);
    };
    

    实例:长度可变的整形数组类

    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.klength();++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
    }
    
    class CArray{
      int size;//数组元素的个数
      int *ptr;//指向动态分配的数组
      public:
      CArray(int s = 0); //s代表数组元素的个数
      CArray(CArray &a);
      ~CArray();
      void push_back(int v);//用于在数组尾部添加一个元素v
      CArray & operator=(const CArray & a); //用于数组对象间的赋值
      int length(){return size;}//返回数组元素个数
      int & CArray::operator[](int i) //返回值为int不行,不能支持a[i] = 4
      {//用以支持根据下标访问数组元素,n=a[i] 和a[i]=4这样的语句,如果一个函数调用的返回值不是引用,我们不能把它写在等号左边(非引用的函数返回值不可以作为左值使用)
        return ptr[i];
      }
    };
    
    CArray::CArray(int s):size(s)
    {
      if(s == 0)
        ptr == NULL;
      else
        ptr = new int[s];
    }
    
    CArray::CArray(CArray &a){
      if(!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) 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;
    }//CArray & CArray::operator=(const CArray &a)
    
    void CArray::push_back(int v)//写起来简单但是效率较低的做法,比较好的做法是预先分配稍多的空间,也就是vetcor
    { //在数组尾部添加一个元素
      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;//加入新的数组元素
    }
    

    流插入运算符和流提取运算符的重载

    问题引入

    • cout<<5<<"this" 为什么能够成立
    • cout是什么?"<<"为什么能用在cout上

    流插入&流提取运算符的重载

    • cout是在iostream中定义的,ostream类的对象

    • "<<"能用在cout上是因为,在iostream里对"<<"进行了重载

    • 如何重载才能使得cout << 5;//等价于cout.operator<<(5);

      cout<< "this"//等价于cout.operator<<("this");

      都能成立?

      • 重载成ostream类的成员函数

        void ostream::operator<<(int n)
        {
        ...//输出n的代码
        return;
        }
        
    • 如何重载才能使得cout<<5<<"this"//连续书写

      能够成立?

      • 重载成ostream类的成员函数

        ostream & ostream::operator<<(int n)//和上面那个单独实现的返回值是不同的
        {
        ...//输出n的代码
        return *this;
        }
        ostream & ostream::operator<<(const char* n)
        {
        ...//输出n的代码
        return *this;
        }
        
    • cout<<5<<"this" 本质上的函数调用的形式是什么?

      • cout.operator<<(5).operator<<("this");

    例题

    • 假定下面程序输出为5hello,应该补写什么

      class CStudent{
        public: int nAge;
      };
      int main(){
        CStudent s;
        s.nAge = 5;
        cout << s << "hello";
        return 0;
      }
      //这里只能重载为全局函数,因为cout对象的ostream类已经在iostream里写好了
      
    • 答案

      ostream & operator <<(ostream & o, const CStudent & s){//重载成全局函数,操作数数目=函数的参数个数
        o<<s.nAge;
        return o;
      }
      
    • 假定c是Complex复数类的对象,现在希望写"cout << c;",就能以"a+bi"的形式输出c的值,写"cin>>c;",就能从键盘接受"a+bi"形式的输入,并且使得c.real = a, c.imag = b;

    • 答案:

      #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, const Complex &c);
      };
      ostream & operator << (ostream & os, const Complex &c)
      {
        os << c.real << "+" <<c.imag << "i"; //以"a+bi的形式输出
        return os;
      }
      istream & operator >> (istream & is, const Complex &c)
      {
        string s;
        is >> s;//将"a+bi"作为字符串读入,"a+bi"中间不能有空格
        int pos = s.find("+",0);
        string sTmp = s.substr(0,pos);//分离出代表实部的字符串
        c.real = atof(sTmp.c_str());//atof库函数能将const char*指针指向的内容转换成float
        sTmp = s.substr(pos+1,s.length()-pos-2);//分离出代表虚部的字符串
        c.imag = atof(sTmp.c_str());
        return is;
      }
      

    自增&自减运算符的重载

    基本概念

    • 自加++/自减--运算符有前置/后置之分
    • 前置运算符作为一元运算符重载
      • 重载为成员函数
        • T operator++();
        • T operator--();
      • 重载为全局函数
        • T operator++(T);
        • T operator--(T);
      • ++obj,obj.operator++(),operator++(obj)都调用上述函数
    • 后置运算符作为二元运算符重载
      • 多写一个参数,参数本身是无意义的,只是为了区别前置后置
      • 重载为成员函数
        • T operator++(int);
        • T operator--(int);
      • 重载为全局函数
        • T operator++(T,int);
        • T operator--(T,int);
      • obj++,obj.operator++(0),operator++(obj,0)都调用上述函数

    举例

    • int main(){
        CDemo d(5);
        cout << (d++) <<","; //=d.operator++(0);
        cout << d << ",";
        cout << (++d) << ","; //=d.operator++();
        cout << d << endl;
        cout << (d--) <<","; //=operator--(d,0)
        cout<< d << ",";
        cout << (--d) << ","; //=operator--(d);
        cout << d << endl;
        return 0;
        //输出结果 5,6,7,7
      7,6,5,5
      }
      
    • 答案:

      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){//后置++
        CDemo tmp(*this);//记录修改前的对象,因为成员变量无指针,所以此时复制构造函数不需要重载
        n++;
        return tmp;//返回修改前的对象
      }
      
      CDemo operator--(CDemo &d){//前置--
        d.n--;
        return d;
      }
      
      CDemo operator--(CDemo &d, int k){//后置--
        CDemo tmp(d);
        d.n--;
        return tmp;
      }
      
    • 注意:

      operator int(){ return n;}
      //int 所为一个类型强制转换运算符被重载
      Demo s;
      (int) s; //等效于s.int();
      
      • 类型强制转换运算符被重载时
        • 不能写返回值类型
        • 实际上其返回值类型为类型强制转换运算符所代表的类型

    运算符重载注意事项

    • C++不允许定义新的运算符
    • 重载后运算符的含义应该符合日常习惯
      • complex_a + complex_b
      • word_a > word_b
      • data_b = data_a + n
    • 运算符重载不改变运算符的优先级
    • 以下运算符不能重载: "."".*"::""?:""sizeof"
    • 重载运算符()[]->或者赋值运算符=时,重载函数必须声明为类的成员函数

    习题

    Choice1

    • 如果将运算符 “ * ” 重载为某个类的成员运算符(也即成员函数),则该成员函数的参数个数是?
      • 0个(指针的解引用运算)或1个(算数乘法运算)

    注:填空题在Coursera提交时,文件中只需出现填进去的内容即可

    Quiz 1

    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    class Complex {
    private:
        double r,i;
    public:
        void Print() {
            cout << r << "+" << i << "i" << endl;
        }
        Complex & operator = (string s){
            int pos = s.find("+",0);
            string sTmp = s.substr(0,pos);//分离出代表实部的字符串
            r = atof(sTmp.c_str());//atof库函数能将const char*指针指向的内容转换成float
            sTmp = s.substr(pos+1,s.length()-pos-2);//分离出代表虚部的字符串
            i = atof(sTmp.c_str());
            return *this;
        }
    };
    int main() {
        Complex a;
        a = "3+4i"; a.Print();
        a = "5+6i"; a.Print();
        return 0;
    }
    

    Quiz 2

    #include <iostream>
    using namespace std;
    class MyInt {
        int nVal;
    public:
        MyInt(int n) { nVal = n; }
        int ReturnVal() { return nVal; }
    // 在此处补充你的代码
        MyInt & operator- (int i){
            nVal-= i;
            return *this;
        }
    };
    int main () {
        MyInt objInt(10);
        objInt-2-1-3;
        cout << objInt.ReturnVal();
        cout <<",";
        objInt-2-1;
        cout << objInt.ReturnVal();
        return 0;
    }
    

    Quiz 3

    #include <iostream>
    #include <cstring>
    using namespace std;
    // 在此处补充你的代码
    class Array2{
    private:
        int *p;
        int x,y;
    public:
        Array2(int i, int j) :x(i),y(j){p = new int[i*j];}
        Array2():x(0),y(0),p(NULL){}
        int* operator[](int i) {
            return (p + i * y);
        }//注意!这里是返回指针而不是返回对象的引用!这样第二个[]就能直接取出数值了!!
        int& operator()(int i,int j){
            return p[i*y + j];
        }
        Array2& operator=(const Array2& a){
            if(a.p == NULL){
                p = NULL;
                return *this;
            }
            if(p) delete[] p;
            x = a.x;
            y = a.y;
            p = new int[x*y];
            memcpy(p,a.p,sizeof(int)*x*y);
            return *this;
        }
    
    };
    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;
    }
    

    Quiz4 大整数的加减乘除

    #include <iostream>
    #include <string>
    #include <cstdlib>
    #include <algorithm> //reverse函数所需的头文件
    using namespace std;
    
    class BigInt
    {
    private:
        string values;//保存所有位上的数字
        bool flag;//true表示正数,false表示负数,0默认为正数
        inline int compare(string s1,string s2)
        {
            if(s1.size() < s2.size())
                return -1;
            else if(s1.size() > s2.size())
                return 1;
            else return s1.compare(s2);
        }
    
    public:
        BigInt():values("0"),flag(true){ };
        BigInt(string str)//类型转换构造函数(默认为正整数)
        {
            values = str;
            flag = true;
        }
    
    public:
        friend ostream& operator << (ostream& os,const BigInt& bigInt);//重载输出操作符
        friend istream& operator >> (istream& is,BigInt& bigInt);//重载输入操作符
        BigInt operator+ (const BigInt& rhs);//加法操作符重载
        BigInt operator- (const BigInt& rhs);//减法操作符重载
        BigInt operator* (const BigInt& rhs);//乘法操作符重载
        BigInt operator/ (const BigInt& rhs);//除法操作符重载
    };
    /*
     * 重载流提取运算符'>>',输出一个整数
     */
    ostream& operator << (ostream& os, const BigInt& bigInt)
    {
        if(!bigInt.flag)
        {
            os << '-';
        }
        os << bigInt.values;
        return os;
    }
    /*
     * 重载流插入运算符'>>',输入一个正整数
     */
    istream& operator >> (istream& is, BigInt& bigInt)
    {
        string str;
        is >> str;
        bigInt.values = str;
        bigInt.flag = true;
        return is;
    }
    /*
     * 两个正整数相加
     */
    BigInt BigInt::operator+(const BigInt &rhs)
    {
        BigInt ret;
        ret.flag = true;//正数相加恒为正数
        string lvalues(values),rvalues(rhs.values);
        //特殊情况处理
        if(lvalues == "0")
        {
            ret.values = rvalues;
            return ret;
        }
        if(rvalues == "0")
        {
            ret.values = lvalues;
            return ret;
        }
        //调整s1与s2的长度
        unsigned int i, lsize, rsize;
        lsize = lvalues.size();
        rsize = rvalues.size();
        if(lsize < rsize)
        {
            for (i = 0; i < rsize - lsize; i++)//在lvalues左边补0
            {
                lvalues = "0" + lvalues;
            }
        }
        else
        {
            for (i = 0; i < lsize - rsize; i++)//在rvalues左边补0
            {
                rvalues = "0" + rvalues;
            }
        }
        //处理本质情况
        int n1,n2;
        n2 = 0;
        lsize = lvalues.size();
        string res = "";
        reverse(lvalues.begin(),lvalues.end());//颠倒字符串,方便从低位起计算
        reverse(rvalues.begin(),rvalues.end());
        for (int i = 0; i < lsize; i++) {
            n1 = (lvalues[i] - '0' + rvalues[i] - '0' + n2) % 10; //n1代表当前位的值
            n2 = (lvalues[i] - '0' + rvalues[i] - '0' + n2) / 10; //n2代表进位
            res = res + char(n1 + '0');
        }
        if(n2 == 1) //当计算完毕后,最终还留有一个进位的时候
        {
            res = res + "1";
        }
        reverse(res.begin(), res.end());
    
        ret.values = res;
        return ret;
    }
    /*
     * 两个正整数相减
     */
    BigInt BigInt::operator-(const BigInt &rhs)
    {
        BigInt ret;
        string lvalues(values), rvalues(rhs.values);
        //处理特殊情况
        if(rvalues == "0")
        {
            ret.values = lvalues;
            ret.flag = true;
            return ret;
        }
        if(lvalues == "0")
        {
            ret.values = rvalues;
            ret.flag = false;
            return ret;
        }
        //调整s1与s2的长度
        unsigned int i, lsize, rsize;
        lsize = lvalues.size();
        rsize = rvalues.size();
        if(lsize < rsize)
        {
            for (i = 0; i < rsize - lsize; i++)//在lvalues左边补0
            {
                lvalues = "0" + lvalues;
            }
        }
        else
        {
            for (i = 0; i < lsize - rsize; i++)//在rvalues左边补0
            {
                rvalues = "0" + rvalues;
            }
        }
        //调整使被减数大于减数
        int t = lvalues.compare(rvalues);//相等返回0,str1<str2返回负数,str1>str2返回正数
        if(t<0)
        {
            ret.flag = false;
            string tmp = lvalues;
            lvalues = rvalues;
            rvalues = tmp;
        }
        else if(t == 0)
        {
            ret.values = "0";
            ret.flag = true;
            return ret;
        }
        else
        {
            ret.flag = true;
        }
        //处理本质情况
        unsigned int j;
        lsize = lvalues.size();
        string res = "";
        reverse(lvalues.begin(),lvalues.end());//颠倒字符串,方便从低位开始计算
        reverse(rvalues.begin(),rvalues.end());
        for (int i = 0; i < lsize; i++)
        {
            if(lvalues[i] < rvalues[i])//若不足,向前借一位
            {
                j = 1;
                while (lvalues[i+j] == '0')
                {
                    lvalues[i+j] = '9';
                    j++;
                }
                lvalues[i+j] -= 1;
                res = res + char(lvalues[i] + ':' - rvalues[i]);
            }
            else
            {
                res = res + char(lvalues[i] - rvalues[i] + '0');
            }
        }
        reverse(res.begin(),res.end());
        res.erase(0,res.find_first_not_of('0'));//去掉前导0
    
        ret.values = res;
        return ret;
    }
    
    /*
    两个正整数相乘
    */
    BigInt BigInt::operator*(const BigInt &rhs)
    {
        BigInt ret;
        string lvalues(values),rvalues(rhs.values);
        //处理特殊情况
        if(lvalues == "0" || rvalues == "0")
        {
            ret.values = "0";
            ret.flag = true;
            return ret;
        }
    
        unsigned int lsize, rsize;
        lsize = lvalues.size();
        rsize = rvalues.size();
        string temp;
        BigInt res,itemp;
        //让lvalues的长度最长
        if (lvalues < rvalues)
        {
            temp = lvalues;
            lvalues = rvalues;
            rvalues = temp;
            lsize = lvalues.size();
            rsize = rvalues.size();
        }
        //处理本质情况
        int i, j, n1, n2, n3, t;
        reverse(lvalues.begin(),lvalues.end());//颠倒字符串,方便从低位开始计算
        reverse(rvalues.begin(),rvalues.end());
        for (i = 0; i < rsize; i++) {
            temp = "";
            n1 = n2 = n3 = 0;
            for (j = 0; j < i; j++)
            {
                temp = temp + "0";
            }
            n3 = rvalues[i] - '0'; //n3记录乘数的字面值
            for (j = 0; j < lsize; j++) {
                t = (n3*(lvalues[j] - '0') + n2);
                n1 = t % 10;//n1记录当前位置的值
                n2 = t / 10;//n2记录进位的值
                temp = temp + char(n1 + '0');
            }
            if(n2)
            {
                temp = temp + char(n2 + '0');
            }
            reverse(temp.begin(), temp.end());
            itemp.values = temp;
            res = res + itemp; //直接就用上了刚刚重构的加法~~~
        }
        ret = res;
        return ret;
    }
    /*
     * 两个正整数相除
     */
    BigInt BigInt::operator/(const BigInt &rhs)
    {
        BigInt ret;
        string lvalues(values),rvalues(rhs.values);
        string quotient;
        //处理特殊情况
        if(rvalues == "0")
        {
            ret.values = "error";//输出错误
            ret.flag = true;
            return ret;
        }
        if(lvalues == "0")
        {
            ret.values = "0";
            ret.flag = true;
            return ret;
        }
        if(compare(lvalues, rvalues) < 0)
        {
            ret.values = "0";
            ret.flag = true;
            return ret;
        }
        else if(compare(lvalues,rvalues) == 0)
        {
            ret.values = "1";
            ret.flag = true;
            return ret;
        }
        else
        {
            //处理本质情况
            string temp;
            unsigned int lsize,rsize;
            lsize = lvalues.size();
            rsize = rvalues.size();
            int i;
            if(rsize > 1) temp.append(lvalues,0,rsize-1); //如果除数的位数大于1,从被除数中取出除数个位数的数(从大到小)
            for (int i = rsize - 1; i < lsize; i++) {
                temp = temp + lvalues[i];//一个一个往上补
                //试商
                for (char c = '9'; c >= '0' ; c--)
                {
                    BigInt t = (BigInt)rvalues * (BigInt)string(1,c);
                    BigInt s = (BigInt) temp - t;
    
                    if(s.flag == true)
                    {
                        temp = s.values;
                        quotient = quotient + c;
                        break;
                    }
    
                }
            }
        }
        //去除前导0
        quotient.erase(0,quotient.find_first_not_of('0'));
        ret.values = quotient;
        ret.flag = true;
        return ret;
    }
    
    int main()
    {
        BigInt a,b,result;
        char op;
        cin >> a >> op >> b;
        switch(op)
        {
            case '+':result = a + b; break;
            case '-':result = a - b; break;
            case '*':result = a * b; break;
            case '/':result = a / b; break;
            default:break;
        }
        cout << result << endl;
        return 0;
    }
    //这个答案也是抄写的别人的,抄下来感觉受益匪浅,写的真好!
    //就是不知道自己啥时候能有写这种代码的水平啊!:(
    
  • 相关阅读:
    apue学习笔记(第十二章 线程控制)
    apue学习笔记(第十一章 线程)
    apue学习笔记(第十章 信号)
    apue学习笔记(第九章 进程关系)
    apue学习笔记(第八章 进程控制)
    apue学习笔记(第七章 进程环境)
    apue学习笔记(第六章 系统数据文件和信息)
    apue学习笔记(第五章 标准I/O)
    apue学习笔记(第四章 文件和目录)
    apue学习笔记(第三章 文件I/O)
  • 原文地址:https://www.cnblogs.com/maimai-d/p/12914032.html
Copyright © 2020-2023  润新知