对抽象数据类型也能够直接使用C++提供的运算符
举例:
对已有运算符赋予多重的含义
目的是扩展C++中提供的运算符的适用范围,以用于类所表示的抽象数据类型
实质是函数重载
返回值类型 operator 运算符 (形参表)
{
......
}
在程序编译时
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;
}
//这个答案也是抄写的别人的,抄下来感觉受益匪浅,写的真好!
//就是不知道自己啥时候能有写这种代码的水平啊!:(
Coursera课程笔记----C++程序设计----Week4
原文:https://www.cnblogs.com/maimai-d/p/12914032.html