运算符重载实例:可变长整型数组
问题
写一个可变长整型数组类CArray
,并且满足以下程序的正常运行
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] << " ";
}
return 0;
}
程序输出结果
0 1 2 3 4
0 1 2 100 4
分析
需求分析
-
CArray
需要两个成员变量arr
和len
,整型指针arr
指向动态分配的数组,整型len
表示数组元素的个数. - 构造函数.可以缺省的指定数组长度(程序中没有强求).
- 复制构造函数.支持
CArray a4(a);
语句的正确执行.在执行初始化语句时会调用复制构造函数构造对象,为了避免使用默认的复制构造函数而引起的浅拷贝的问题,需要自己重写复制构造函数. - 析构函数.释放动态分配的数组内存.
-
push_back(int i)
成员函数.用于在数组尾部添加一个元素i
. - 重载运算符
=
.用于数组对象间的赋值 -
length()
成员函数.返回数组元素的个数 - 重载运算符
[]
.支持n=a[i];
和a[i]=4;
这样的语句.
代码实现分析
构造函数CArray(int l = 0);
缺省数组长度的构造函数,当指定数组长度时开辟相应长度的数组空间,否则初始为NULL
.
复制构造函数CArray(CArray& a);
用同类对象对对象初始化时会调用复制构造函数初始化对象,如语句CArray a4(a);
.为了避免浅拷贝的问题,需要重写复制构造函数.在复制构造函数中,为新的对象重新分配一片存储空间,避免和之前的对象a
指向同一片内存空间.首先判断一下a
是否为NULL
,如果为NULL
,则直接将数组指针指向NULL
即可,否则新开辟一块a.len
大小的内存空间,使用memcpy
内存拷贝函数进行数据拷贝,最后设置好数组长度.
析构函数~CArray();
在释放内存空间之前,避免重复释放内存出错,先判断一下数组指针arr
是否为NULL
.
添加数组元素push_back(int i);
如果数组本来不为空,分配一个比原来长度加一的内存空间,赋给一个临时数组指针,然后将原来的数组内容拷贝到这个临时的数组中,然后再释放原来的内存空间,然后让数组指针指向刚才分配的那片内存的地址.如果数组本来为空,则只需要分配一个长度为1的内存空间.最后,向数组尾部加入新的数组元素,并且更新数组长度.
补充:老师说该方式效率较低,可以采取每次内存不够的时候分配两倍大的空间,可以减少分配内存空间的次数.我思考了一下,如果采取这种办法的话就需要两个成员变量size
和len
,size
指示内存空间的大小,len
指示当前数组元素,才可以实现.
重载运算符=
`CArray& operator=(const CArray& a);`
为了实现变长数组对象之间的正确赋值,避免浅拷贝问题,在重载=
运算符时,=左右两边的数组对象大小和内容都一样,但不在同一片内存空间.那么思考一个问题,当遇到a=a;
语句时,会出现什么现象?为了避免a=a;
这样的赋值出错,首先应该先判断一下=
左右两边的对象是否相等,如果相等则直接返回本对象.接下来考虑两个对象不等的情况.
-1- 如果右边的对象a
里面的数组是空的,则释放本对象数组内存,并且将数组指针赋为NULL
,更新len
为0
,返回本对象的引用;
-2- 如果原来的数组对象中有足够大的空间,不需要再重新分配新的内存空间.否则释放原有空间,分配新的内存空间.
-3- 拷贝右边对象a
中的数据,更新len
,返回本对象的引用,结束.
重载运算符[]
int& operator[](int index);
注意要支持n=a[i];
和a[i]=4;
这样的语句,返回值为int&
.
完整代码
#include<iostream>
#include<string.h>
using namespace std;
//可变长数组对象
class CArray{
public:
//构造函数,l代表数组元素的个数
CArray(int l = 0);
//复制构造函数
CArray(CArray& a);
//析构函数
~CArray();
//取长度,返回元素个数
const int length();
//插入函数,用于在数组尾部添加一个元素i
void push_back(int i);
//重载=,用于可变长数组对象间的赋值
CArray& operator=(const CArray& a);
//重载[],支持n=a[i];和a[i]=4;这样的语句,返回值为int&
int& operator[](int index);
private:
int len; //数组元素的个数
int* arr; //指向动态分配的数组
};
//构造函数
CArray::CArray(int l):len(l){
if(0 == l){
arr = NULL;
}else{
arr = new int[l];
}
}
//复制构造函数
CArray::CArray(CArray& a){
if(!a.arr){
arr = NULL;
len = 0;
return;
}
arr = new int[a.len];
memcpy(arr, a.arr, sizeof(int)*a.len);
len = a.len;
}
//析构函数
CArray::~CArray(){
if(arr){
delete[] arr;
}
}
//插入函数
void CArray::push_back(int i){
if(arr){
int* arrCpy = new int[len+1];
memcpy(arrCpy, arr, sizeof(int)*len);
delete[] arr;
arr = arrCpy; //数组之间赋值
}else{
arr = new int[1];
}
arr[len++] = i; //加入新的数组元素
}
//重载=
CArray& CArray::operator=(const CArray& a){
if(arr == a.arr){ //a=a;
return *this;
}
if(!a.arr){
if(arr){
delete[] arr;
}
arr = NULL;
len = 0;
return *this;
}
if(len < a.len){
if(arr){
delete[] arr;
}
arr = new int[a.len];
}
memcpy(arr, a.arr, sizeof(int)*a.len);
len = a.len;
return *this;
}
//重载[]
int& CArray::operator[](int index){
if(index < 0 || index > length()){
return arr[0];
}else{
return arr[index];
}
}
//取长度
const int CArray::length(){
return len;
}
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] << " ";
}
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。