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 *类型的成员变量,指向动态分配的存储空间
  • 该存储空间用于存放'\0'结尾的字符串
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\n7,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;
}
//这个答案也是抄写的别人的,抄下来感觉受益匪浅,写的真好!
//就是不知道自己啥时候能有写这种代码的水平啊!:(
posted @ 2020-05-19 00:23  maimai_d  阅读(146)  评论(0编辑  收藏  举报