Coursera課程筆記----C++程序設計----Week4

運算符重載(week 4)

運算符重載-基本概念

運算符

  • C++預約義表示對數據的運算
    • +,-,*,/.....
    • 只能用於基本的數據類型
      • 整形,實型,字符型,邏輯型等
  • C++提供了數據抽象的手段➡️用戶本身定義數據類型--
    • 調用類的成員函數,操做它的對象
  • 類的成員函數操做對象時,有時候會很不方便
    • 在數學上,兩個複數能夠直接進行+/-等
    • 在C++中,直接將+和-用於複數是不容許的

運算符重載

  • 抽象數據類型也可以直接使用C++提供的運算符ios

    • 程序更簡潔
    • 代碼更容易理解
  • 舉例:數組

    • complex_a和complex_b兩個複數對象
    • 求兩個複數的和,但願能直接寫成:complex_a +
  • 對已有運算符賦予多重的含義app

    • 使同一運算符做用於不一樣類型的數據時,產生不一樣的行爲
  • 目的是擴展C++中提供的運算符的適用範圍,以用於類所表示的抽象數據類型函數

  • 實質是函數重載ui

    返回值類型 operator 運算符 (形參表)this

    {spa

    ......指針

    }code

  • 在程序編譯時對象

    • 把含運算符的表達式,看成對運算符函數的調用
    • 把運算符的操做數,看成運算符函數的參數
    • 運算符屢次被重載時,根據實參的類型決定調用哪一個運算符函數
    • 運算符能夠被重載爲普通函數,也能夠被重載爲類的成員函數
    • 重載爲普通函數時,參數個數爲運算符目數
    • 重載爲成員函數時,參數個數爲運算符目數-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;
}
//這個答案也是抄寫的別人的,抄下來感受受益不淺,寫的真好!
//就是不知道本身啥時候能有寫這種代碼的水平啊!:(
相關文章
相關標籤/搜索