模板类之(数组)

一、数组类

//shuzu.h

#ifndef ARRAY_CLASS #define ARRAY_CLASS #include #include using namespace std; #ifndef NULL const int NULL = 0; #endif //错误类型集合:数组大小错误,内存分配错误和下标越界错误 enum ErrorType{invalidArraySize,memoryAllocationError,indexOutOfRange}; //错误信息 char *errorMsg[] = {"Invalid array size","Memory allocation error","Invalid index"}; //数组类模板声明 template class Array { private: T* alist; int size; void Error(ErrorType error,int badIndex = 0)const; public: Array(int sz = 50); Array(Array& A); ~Array(void); Array& operator = (const Array& rhs); T& operator[](int); operator T*(void)const; int ListSize(void)const; void Resize(int sz); } //以下为类成员函数的定义 //模板类Error实现错误信息输出功能 template void Array::Error(ErrorType error,int badIndex)const { std::cout_of_range< void Array::Array(int sz) { if(sz<0) Error(InvalidArraySize); size = sz; alistv = new T[size]; if(alist == NULL) Error(memoryAllocationError); } //析构函数 template Array::~Array(void) { delete[]alist; } //拷贝构造函数 template Array::Array(const Array& X) { int n = X.size; size = n; alist = new T[size]; if(alist == NULL) Error(memoryAllocationError); T* srcptr = X.alist; T* destptr = alist; while(n--) //逐个赋值数组元素 *destptr++ = *srcptr++; } //重载“=”运算符,实现对象之间的整体赋值 template Array& Array::operator =(const Array& rhs) { int n = rhs.size; //如果本对象中数组的大小与rhs不同,则删除数组原有内存,然后重新分配 if(size != n) { delete [] alist; alist = new T[n]; if(alist == NULL) Error(memoryAllocationError); size = n; //从rhs向本对象复制元素 T* srcptr = rhs.alist; T* destptr = alist; while(n--) *destptr++ = *srcptr++; //返回当前对象的引用 return *this; } } //重载下标运算符,实现与普通数组一样通过下标访问元素,并且具有下标越界检查、 template T& Array::operator [](int n) { if(n<0 || n > size) Error(indexOutOfRange,n); return alist[n]; } //重载指针转换运算符,将Array类的对象名转换成T类型的指针, //指向当前对象中的私有数组 //因而可以像使用普通数组首地址一样使用Array类的对象名 template Array::operator T*(void)const { return alist; } //取当前数字大小 template int Array::ListSize(void)const { return size; } //将数组大小改为sz template void Array::Resize(int sz) { if(sz < 0) Error(invalidArraySize); if(sz = size) return ; T* newlist = new T[sz]; if(newlist == NULL) Error(memoryAllocationError); int n = (sz > size) ? sz :size; //将size和sz中较小的一个赋给n //将原有数组中的前n个元素复制到新数组中 T* srcptr = alist; //原有数组首地址 T* destptr = newlist; //新数组首地址 while(n--) *destptr++ = *srcptr++; delete [] alist; //删除原有数组 alist = newlist; //使alist指向新数组 size = sz; //更新size } #endif //ARRAY_CLASS

 

二、应该要注意的几个问题:

1、为什么拷贝构造函数要这么复杂?为什么不是简单的赋值?

——这涉及到深拷贝和浅拷贝的问题。简单的对对象成员赋值只能实现浅拷贝,浅拷贝会造成内存访问的安全性问题(同一块内存被释放两次)

 

2、为什么有些函数返回值是对象的引用,改为返回对象值可以吗?

——如果一个函数的返回值是一个对象值,它被认为是一个常量,当然不能成为左值。如果返回引用,引用的实质就是变量(对象)的别名,通过变量(对象)的别名当然可以改变变量(对象)的值。

eg:int a,b = 5;

(a=b)++;

这在C++中是允许的,运行后a的值是6,因此运算符“[ ]”和运算符“=”返回的都是引用类型。

另外,C++语法还规定,“=”,“[ ]”,“->”,“( )”都只能重载为成员函数,而且“=”运算符函数是不能被继承的。

所以重载运算符[]和运算符=都返回引用。

 

3、重载指针运算有必要吗?

看一个程序:

#include using namespace std; void read(int* p,int n); void main() { int a[10]; read(a,10); } void read(int* p , int n) { for(int i = 0;i < n;i++) cin>>p[i]; }  

这里函数read的第一个形参是int *类型,而数组名a也是一个int型的指针常量,类型恰好是匹配的。但是如果希望像使用普通数组一样使用Array类的对象,将上述main函数改为如下:

 

void main() { Arraya(10); read(a,10); } 

这里形参和实参不同,编译系统会尝试进行自动类型转化,将类对象名a转换成形参的int*。由于a是自定义的对象,因此无法实现这一转换,因此需要我们自行编写重载的指针类型转换函数。

 

4、为什么转换指针函数体内有return语句,但是函数却没有返回值,连void都没有?

——这是C++语法规定:重载类型转换运算符时,不允许指定返回值类型(也不要写void)

 


 

三、应用上面的Array类:

求范围在2~n之间的质数,n在程序运行时由键盘输入

#include #include #include"shuzu.h" using namespace std; void main(void) { Array A(10); //初始化存放质数的数组,初始状态有10个元素 int n; int primecount = 0,i,j; cout<<"Enter a value >= 2 as upper limit for prime numbers:"; cin>>n; A[primecount++] = 2; //2是一个质数 for(i = 3 ; i i/2) A[primecount++] = i; } //输出质数数组 for(i = 0; i < primecount; i++) { cout<

 

你可能感兴趣的:(C++)