C++:长度可变的整型数组类

 这个是按照北京大学郭老师c++程序设计所作的课堂笔记。

/*动态可变长数组(运算符重载)的使用
*/


#include<iostream>
using namespace std;
class CArray {
	int size;							//数组元素的个数,(有一个length成员函数,能输出数组的长度)
	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; }		//返回数组元素个数
	/*
	下面函数的作用:
	用以支持根据下标访问数组元素,如n=a[i]和a[i]=4这样的语句,
	a[]a里面的数组元素在ptr指向的动态分配的空间中。
	下面这个函数的类型是什么???
	[]是双目运算符(一个在里面,一个在外面)只有一个参数,在成员函数中,数组的下标,在这个成员函数中运用

	*/
	int& operator[](int i) {			//返回值的类型为什么是int的引用,为甚么int不行???
										//用n=a[]可以,但是用a[]=4就是不可以了
										//如果一个函数的返回值不是引用的话就不能作为=(赋值运算符)的左值、
										//同时****希望能修改a[]的值,如果是一个数值则不会修改数值,只有是ptr[]的引用才能让a[]被修改
		return ptr[i];					//返回一个数值,a[]的数值
	}
};
CArray::CArray(int s) :size(s) {		//构造函数,就已经包含多少元素//size()初始化列表
	if (s == 0)
		ptr = NULL;
	else
		ptr = new int[s];
}
CArray::CArray(CArray& a) {				//复制构造函数,深拷贝	
	if(!a.ptr) {						//主要用来判断如果指针是空指针的时候,
										//进行出错处理和return 出去。说明有错误了。
		ptr = NULL;
		size = 0;
		return;							//return出去
	}
	ptr = new int[a.size];				
	memcpy(ptr, a.ptr, sizeof(int) * a.size);//将a.ptr中的内容复制到ptr中去,并且需要有多少字节的内容,sizeof(int)*a.size
	size = a.size;							
}
CArray::~CArray() {							//释放空间
	if (ptr)delete[]ptr;					//判断是不是空指针,如果不是空指针就释放
}
CArray& CArray::operator=(const CArray& a) {//赋值号的作用是使“=”左边对象里存放的数组,大小和内容都和右边的一样
											//返回值是carray的引用,是为了符合赋值号使用的惯例,在c++中赋值表达式的返回值本来就是赋值号左面的变量的引用,
											//我们遵循这样的习惯,所以赋值号重载后的返回值仍然是CArray的引用
											//如果不是这样的话那么在c++中左值并不是一个引用,而是一个返回的值,那么这个变量就不能作为一个赋值运算符的左值
	if (ptr == a.ptr)						//防止a=a这样的赋值导致出错(特判)
		return *this;						//跳出函数
	if(a.ptr == NULL) {						//引用值的数组
		if (ptr) delete[]ptr;				//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,因为执行完上一个if语句后就来执行这个语句,
												//并且最后一种情况和if(处理size<a.size)之后需要处理的是一样的东西,所以只需要写一个就行
	size = a.size;
	return*this;
}
void CArray::push_back(int v) {				//这个比较低效应该先用比较长的存储空间(32),若不够再+32
	if (ptr) {								//在尾部加一个新的元素
		int* temPtr = new int[size + 1];	//重新分配空间
		memcpy(temPtr, ptr, sizeof(int) * size);//拷贝元素组内容
		ptr = temPtr;
	}
	else//数组本来是空的
		ptr = new int[1];
	ptr[size++] = v;//加入新的数组元素
}
/*1.要用动态分配内存来存放数组,需要一个指针成员变量
2.动态分配的内存要释放,则需要一个析构函数
3.a2=a,则需要一个重载运算符=函数
4.a2[]成立则需要一个重载[]函数,因为a2是一个类
5.CArray a4(a)则需要一个复制构造函数,并且是深复制,如果是浅复制则动态分配的空间会出错
*/
int main() {									//要编写的可变长数组,使之能如下使用
	CArray a;									//开始的数组是空的
	for (int i = 0; i < 5; ++i)
		a.push_back(i);                         //把五个整数加到数组里,有五个元素了
	CArray a2, a3;
	a2 = a;										//a2是一个新的数组a的内容和a2的内容是一样的,只是存储空间不一样
												//相互分开,此时用重载=运算符
	for (int i = 0; i < a.length(); ++i)		//打印a2,循环输出
		cout << a2[i] << " ";
	a2 = a3;									//把a3复制给a2,但是此时a3是空的所以a2需要释放掉
	for (int i = 0; i < a2.length(); ++i)		//a2没有任何输出因为此时a2是一个空数组了,a2里面没有元素
		cout << a2[i] << "";
	cout << endl;
	a[3] = 100;                                 //赋值100
	CArray a4(a);								//复制构造函数
	for (int i = 0; i < a4.length(); ++i)		
		cout << a4[i] << " ";					//0 1 2 100 4
	cout << endl;
	int c[6] = { 0 };
	CArray b;
	for (int i = 0; i < 8; i++)
		b.push_back(i);
	b = a;
	for (int i = 0; i < b.length(); i++)
		cout << b[i]<<" ";
	cout << endl;
	return 0;									
}

C++圣经《C++程序设计语言 特别版》(C++之父的著作)中说:
,C++之父认为 ,判断指针是否为空,用(p==NULL)或(p!=NULL)的格式  ,这样写是不好的,提倡直接写(p)或(!p)的形式。 在win32开发中,if ( NULL == p )是极好的写法。但不要写成:if ( p == NULL )。
用if判断ptr是否为空指针的例子:
int* ptr;                        //ptr是一个指针
if(!a.ptr) {                        //主要用来判断如果指针是空指针的时候,
                                        //进行出错处理和return 出去。说明有错误了。
        ptr = NULL;
        size = 0;
        return;                            //return出去
    }
*******************************************************************************
!逻辑非运算符,用来逆转操作数的状态,使真变假,使假变真 
例如:  !ptr(ptr是一个指针),如果ptr=NULL,则该表达式为真;
*******************************************************************************
int *P=NULL;//这里的NULL指的是指针指向的地址没有数值;
*******************************************************************************
赋值表达式:
左值:表达式可以引用到一个对象,并且这个对象是一块内存空间并可以检测和存储,这个表示即是左值。
右值:直接引用了一个存储在内存地址中的数据。
左值是一个对象或变量,代表一个固定地址,而没有固定地址的临时对象或临时变量既是右值,不能代表一个固定地址
 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值