coursera---C++程序设计重点笔记--week4

课程地址: https://www.coursera.org/learn/cpp-chengxu-sheji

1.1 运算符重载的基本概念

  • 运算符重载概念的引出
    c++预定义的运算符只能应用与基本的数据类型int,float,bool,
    有时候需要对一些自定义的数据类型进行操作 对两个复数类进行 相加
  • 运算符重载概念
    运算符重载的实质是函数重载
返回值类型 operator 运算符(形参表)
{
...
}
  • 运算符重载的注意事项
  1. * . :: sizeof 三目除这些运算符之外,其它运算符都可以重载
  2. 重载之后的运算符不能改变原来的 结合性优先级
  3. 运算符重载的目的应当是对原运算符功能的扩充,以适应更多数据类型。不能毫无依据的进行运算符重载

1.2 赋值运算符的重载

赋值运算符两边的类型可以不匹配
赋值运算符只能重载为成员函数 why

例子:
编写一个长度可变的字符串类string

  • 包含一个char *类型的成员变量
class String{
private:
	char * str;
public:
	String():str(NULL){}	//初始化成员列表
	const char *c_str() {return str;}
	char *operator= (const char *s);
	~String();
}
"note: 如果在类里面定义成员函数,则成员函数后面不加分号。"
char * Sring::operator=(const char &s){
	if(str == s.str) return *this;
	if(str) delete [] str; //如果不为空,先清空
		if(s){
			str = new char[strlen(s)+1];
			strcpy(str,s);
		}else
			str = NULL;
	}

重载赋值运算符的意义—浅复制和深复制
一般类都是浅复制,深复制需要自己定义

  • 浅复制/浅拷贝
    浅拷贝只是拷贝指针地址,没有拷贝内存空间
  • 深拷贝

2.1 运算符重载为友元函数

为什么要将运算符重载为友元函数,举了一个例子:
比如定义了一个complex类,在类里面对赋值运算符进行了重载。
c = c + 5; 这个操作是可以的,但是,c = 5 + c;这个操作就不行了

2.2 实例-长度可变的整型数组类

这节课是郭老师上
给定一个主函数,让你写支撑这个主函数的类

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.length(); i++)
  {
  	cout << a2[i] << " ";
  }
  a2 = a3;
  for (int i = 0; i < a2.length(); i++)
  {
  	cout << a2[i] << " ";
  }
  cout << endl;
  a[3] = 100;
  CArray a4(a);
  for (int i = 0; i <a4.length(); i++)
  {
  	cout << a4[i] << " ";
  }
}

class CArray {
public:
	CArray(int size):size(size) {
		if (size)
			ptr = new int[size];
		else
			ptr = NULL;
	}
	CArray():size(0) {
		ptr = NULL;
	}
	CArray(const CArray &array) {  //在这里面实现深拷贝
		
		if (array.ptr != NULL) {
			this->size = array.size;
			this->ptr = new int[this->size];
			memcpy(this->ptr,array.ptr,sizeof(int)*array.size);
		}
		else {
			this->ptr = NULL;
		}
		
	}
	CArray & operator=(const CArray array) {
		if (array.ptr != NULL) {
			this->size = array.size;
			this->ptr = new int[this->size];
			memcpy(this->ptr, array.ptr, sizeof(int)*array.size);
		}
		else {
			this->ptr = NULL;
			this->size = 0;
		}
		return *this;
	}
	void push_back(int i) {
		size++;
		if (ptr != NULL) {
			int * pTmp = new int[size];
			memcpy(pTmp, ptr, sizeof(int)*size);
			pTmp[size - 1] = i;
			delete[] ptr;
			ptr = pTmp;
		}
		else
		{
			ptr = new int[1];
			ptr[0] = i;
		}
		
	}
	int length() {
		return size;
	}
	int& operator[](int i) {
		return ptr[i];
	}
private:
	int size;
	int *ptr;
};

3.1 流插入运算符和流提取运算符的重载

问题:cout << 5 << “this” ; 为什么成立

  • cout 是在 iostream 中定义的一个 ostream类的对象
  • << 能用在cout上是因为,在iostream里面对 << 运算符进行了重载

引入具体问题:

  1. 怎样的重载才能让 cout << 5; 和 cout <<“this”;和 cout << 5 << “this”;都成立
ostream & operator<<(int i)
{
	//输出 i
	return *this;
}
ostream & operator<<(const char *s)
{
	//输出 s
	return *this;
}

本质上cout << 5 << "this"; ==》 cout.operator<<(5).operator<<("this");

2.补全代码
question

class CStudent{
public: int nAge;
};
int main(){
	CStudent s ;
	s.nAge = 5;
	cout << s <<"hello";
	return 0;
}
"error: 没有与这些操作数匹配的运算符"

最直接的想法在 ostream类中新添加一个对运算符<< 的重载。
但是ostream类已经写好了,不能在里面添加了。
answer

"note:重载为普通函数,操作数的个数等于函数参数的个数"
ostream & operator<<( ostream &op,const CStudent &s) {
	op << s.nAge ;
	return op;
}

note: 如果CStudent中nAge是私有的,那怎么办?
answer

"将<<重载函数定义CStudent类的成友元函数"
friend ostream & operator<<(ostream &op,  CStudent &s)
{
	s.nAge = 0;
	op << s.nAge;
	return op;
}
  • 友元函数的定义写在类里面和外面有什么区别么?
  1. 假定c是Complex复数类的对象,现在希望写“cout << c;”,就能以“a+bi”的形式输出c的值,写“cin>>c;”,就能从键盘接受“a+bi”形式的输入,并且使得c.real = a,c.imag = b。

question

int main() {
	Complex c;
	int n;
	cin >> c >> n;
	cout << c << "," << n;
	return 0;
}

answer

class Complex {
private:
	float real, image;
public:
	Complex():real(0),image(0) {
		
	}
	friend ostream & operator<< (ostream &o, Complex &c);
	friend istream & operator>> (istream &i, Complex &c);
};
ostream & operator<< (ostream &o, Complex &c) {
	o << c.real << "+" << c.image << "i";
	return o;
}
istream & operator>> (istream &i, Complex &c) {
	i >> c.real; getchar();
	i >> c.image; getchar();
	return i;
}

3.2 自增/自减运算符的重载

  • 前置/后置运算符 ++i, i++

  • 前置运算符作为一元运算符重载 ++i

  • 后置运算符作为二元运算符重载 i++

4 测验

4.1 代码填空

输入
无

输出
3+4i

5+6i
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Complex {
private:    
    double r,i;
public:    
    void Print() {
        cout << r << "+" << i << "i" << endl;
    }
// 在此处补充你的代码
};
int main() {
    Complex a;
    a = "3+4i"; a.Print();
    a = "5+6i"; a.Print();
    return 0;
}

answer

Complex& operator=(const char *str)// 在此处补充你的代码
	{
		int length = 0;
		while (str[++length]);
 		char *s = new char[length];
		memcpy(s, str, sizeof(char)*length);
		char * tmp;
		tmp = strtok(s, "+");
		this->r = atof(tmp);
		tmp = strtok(NULL, "i");
		this->i = atof(tmp);
		delete[] s;
		return *this;
	}

4.3 实现Array类

描述
写一个二维数组类 Array2,使得下面程序的输出结果是:

0,1,2,3,

4,5,6,7,

8,9,10,11,

next

0,1,2,3,

4,5,6,7,

8,9,10,11,
#include <iostream>
#include <cstring>
using namespace std;
// 在此处补充你的代码
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;
}

answer

"1. 用指针构建一个二维数组"
"2. 对于a[][]中[]运算符重载的理解"
class Array2 {
	int **ptr;
	int row, column;
public:
	Array2() {
		ptr = NULL;
		row = 0;
		column = 0;
	}
	Array2(int i, int j)  //构建二维数组
	{
		row = i; column = j;
		ptr = new int *[row]; //先构建一个一维指针数组
		for (int k = 0; k < row; k++) //遍历指针数组
			ptr[k] = new int[column]; //指针数组中的每个元素指向 正常的一维数组
	}
	Array2 &operator=(const Array2 &a) { //深拷贝
		if (a.ptr != NULL) {
			this->row = a.row;
			this->column = a.column;
			this->ptr = new int *[a.row];
			for (int k = 0; k < a.row; k++) {
				ptr[k] = new int[a.column];
				memcpy(this->ptr[k], a.ptr[k], sizeof(int)*a.column);
			}
		}
		else {
			this->ptr = NULL;
		}
		return *this;
	}
	int* operator[](int i) {
	//a[i][j] 不能理解成 a.operator[i].operator[j]
	//a[i][j] 要理解乘   (a.operatro[i])[j]  其中 (a.operatro[i])是数组首地址
		return ptr[i];
	}
	int operator()(int i, int j) {
		return ptr[i][j];
	}
};

4.4 大整数的加减乘除

描述
给出两个正整数以及四则运算操作符(+ - * /),求运算结果。

输入
第一行:正整数a,长度不超过100

第二行:四则运算符o,o是“+”,“-”,“*”,“/”中的某一个

第三行:正整数b,长度不超过100

保证输入不含多余的空格或其它字符

输出
一行:表达式“a o b”的值。

补充说明:

1. 减法结果有可能为负数

2. 除法结果向下取整

3. 输出符合日常书写习惯,不能有多余的0、空格或其它字符
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值