动态数组的实现(C++)
这是用 C++ 封装的一个简单的动态数组类模板,它由任意多个位置连续的、类型相同的元素组成,其元素个数可在程序运行性改变,与 vector 的工作原理相同。并且使用这个动态数组实现求 2~n 区间之间不确定个数的质数。有需要可以参考,代码如下:
// Array.h
#pragma once
#include <iostream>
#include <cassert>
using namespace std;
// 数组类模板定义
template <class T>
class Array // 数组类
{
private:
T* list; // T 类型指针,用于存放动态分配的数组内存首地址
int size; // 数组大小
public:
Array(int sz = 50); // 构造函数
Array(const Array<T> &arr); // 拷贝构造函数
~Array(); // 析构函数
// 重载 = 运算符
Array<T>& operator=(const Array<T> &arr);
// 重载 == 运算符
bool operator==(const Array<T> &arr);
// 重载 != 运算符
bool operator!=(const Array<T> &arr);
// 重载 [] 运算符
T& operator[](int i);
// [] 运算符对 const 的重载
const T& operator[](int i) const;
// 重载到 T* 类型的转换,使 Array 对象可以起到 C++ 普通数组的作用
operator T*();
// 到 T* 类型转换操作符针对 const 的重载
operator const T*() const;
// 取数组的大小
int getSize() const;
// 修改数组的大小
void resize(int size);
};
template<class T>
inline Array<T>::Array(int sz)
{
assert(sz >= 0);
size = sz;
list = new T[sz];
}
template<class T>
inline Array<T>::Array(const Array<T>& arr)
{
this->size = arr.size;
list = new T[size];
if (NULL == list)
{
cout << "alloc err!" << endl;
exit(-1);
}
for (int i = 0; i < size; i++)
{
list[i] = arr.list[i];
}
}
template<class T>
inline Array<T>::~Array()
{
delete [] list;
list = NULL;
}
template<class T>
inline Array<T>& Array<T>::operator=(const Array<T>& arr)
{
if (&arr != this)
{
// 如果本对象中数组大小与 arr 不同,则释放数组原有内存,重新分配
if (this->size != arr.size)
{
delete[] list;
this->size = arr.size;
list = new T[this->size];
}
for (int i = 0; i < this->size; ++i)
{
list[i] = arr.list[i];
}
}
return *this;
}
template<class T>
inline bool Array<T>::operator==(const Array<T>& arr)
{
if (this->size != arr.size)
{
return false;
}
// 判断内容是否相同
for (int i = 0; i < this->size; i++)
{
if (this->list[i] != arr.list[i])
{
return false;
}
}
return true;
}
template<class T>
inline bool Array<T>::operator!=(const Array<T>& arr)
{
return !(*this == arr);
}
template<class T>
inline T & Array<T>::operator[](int i)
{
assert(i >= 0 && i < size); // 检查数组下标是否越界
return list[i];
}
template<class T>
inline const T & Array<T>::operator[](int i) const
{
assert(i >= 0 && i < size);
return list[i];
}
template<class T>
inline Array<T>::operator T*()
{
return list; // 返回当前对象中私有数组的首地址
}
template<class T>
inline Array<T>::operator const T*() const
{
return list;
}
template<class T>
inline int Array<T>::getSize() const
{
return size;
}
template<class T>
inline void Array<T>::resize(int size)
{
assert(size >= 0); // 检查 size 是否非负
if (this->size == size)
{
return;
}
T* newList = new T[size];
if (NULL == newList)
{
cout << "alloc err!" << endl;
exit(-1);
}
int n = (size > this->size) ? this->size : size;
for (int i = 0; i < n; i++)
{
newList[i] = list[i];
}
delete[] list;
list = newList;
this->size = size;
}
//==========================================
// Filename : 动态数组的实现(C++)
// Time : 2019年5月5日
// Authonr : 柚子树
// Email : [email protected]
//==========================================
/*
动态数组应用:求范围 2~n 中的质数,n 在程序运行时由键盘输入
分析:质数是大于等于 2 的整数,它只能被 1 或其本身整除。由于本题 n 的值是在运行时输入的,不
能预知用来存放质数的数组大小,需要使用动态数组,动态数组的定义和实现在 Array.h 中
*/
#include <iostream>
#include "Array.h"
using namespace std;
int main()
{
Array<int> arr(10); // 用来存放质数的数组,默认值为 10
int count = 0;
int n;
cout << "Enter a value >= 2 as upper limit for prime numbers: ";
cin >> n;
for (int i = 2; i <= n; ++i)
{
// 检查 i 能否被它小的质数整除
bool isPrime = true;
for (int j = 0; j < count; j++)
{
if (i % arr[j] == 0)
{
isPrime = false;
break;
}
}
// 将 i 写入质数表
if (isPrime)
{
// 如果质数表满了,将其空间加倍
if (count == arr.getSize())
{
arr.resize(count * 2);
}
arr[count++] = i;
}
}
for (int i = 0; i < count; i++)
{
cout << arr[i] << " ";
}
cout << endl;
system("pause");
return EXIT_SUCCESS;
}
运行结果:
注意事项:
我们用C++写类的时候,通常会将.cpp和.h文件分开写,即实现和声明分开写了;但在C++的类模板中,这种写法是错误的。
在《C++编程思想》的第16章的“16.3模板语法”一节给出了答案,以下是下书中原话:
即使是在创建非内联函数定义时,我们还是通常想把模板的所有声明都放入一个头文件中。这似乎违背了通常的头文件规则:“不要放置分配存储空间的任何东西“(这条规矩是为了防止在连接期间的多重定义错误),但模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。
C++中每一个对象所占用的空间大小,是在编译的时候就确定的(C++是编译型语言),在模板类没有被实例化前,编译器是无法知道模板类中使用模板类型的对象的所占用的空间的大小。只有模板被实例化,编译器才知道模板套用的是什么类型,应该分配多少空间。这也就是模板类为什么只是称之为模板,而不是泛型的缘故。
原文链接:C++类模板声明与定义为何不能分开