对抽象数据类型也可以直接使用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; } //这个答案也是抄写的别人的,抄下来感受受益不浅,写的真好! //就是不知道本身啥时候能有写这种代码的水平啊!:(