對抽象數據類型也可以直接使用C++提供的運算符ios
舉例:數組
對已有運算符賦予多重的含義app
目的是擴展C++中提供的運算符的適用範圍,以用於類所表示的抽象數據類型函數
實質是函數重載ui
返回值類型 operator 運算符 (形參表)this
{spa
......指針
}code
在程序編譯時對象
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; }
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;
淺複製/淺拷貝(若是不進行重構,系統會系統生成一個缺省的,會發生淺拷貝現象)
深複製/深拷貝
將一個對象中指針變量指向的內容,複製到另外一個對象中指針成員對象所指的對象
如何實現:在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
爲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是在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" 本質上的函數調用的形式是什麼?
假定下面程序輸出爲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; }
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();
注:填空題在Coursera提交時,文件中只需出現填進去的內容便可
#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; }
#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; }
#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; }
#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; } //這個答案也是抄寫的別人的,抄下來感受受益不淺,寫的真好! //就是不知道本身啥時候能有寫這種代碼的水平啊!:(