刚刚学习了c++模板的知识,模仿标准库vector动态数组写一个Vector模板类:
Vector主要功能
1.通过索引实现访问Vector中的元素
2.add() 向数组末尾添加一个元素,并返回索引
3.remove() 删除指定索引的元素
4.get_size() 返回动态数组中元素的个数
下面是实现代码:
#include <iostream>
using namespace std;
template <class T>
class Vector {
private:
T* data; // 存储数据的指针
int size; // 当前存储的元素个数
int capacity; // 当前分配的存储空间大小
public:
Vector() {
data = NULL;
size = 0;
capacity = 0;
}
~Vector() {
delete[] data;
}
int get_size() {
return size;
}
T& operator[](int index) {
return data[index];
}
int add(const T& element) {
if (size == capacity) {
capacity = (capacity == 0) ? 1 : 2 * capacity;
T* new_data = new T[capacity];
for (int i = 0; i < size; i++) {
new_data[i] = data[i];
}
delete[] data;
data = new_data;
}
data[size] = element;
size++;
return size - 1;
}
void remove(int index) {
if (index >= 0 && index < size) {
for (int i = index; i < size - 1; i++) {
data[i] = data[i + 1];
}
size--;
}
}
Vector(const Vector<T>& other) {
size = other.size;
capacity = other.capacity;
data = new T[capacity];
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
};
int main()
{
Vector<int> vint;
int n, m;
cin >> n >> m;
for (int i = 0; i<n; i++) {
vint.add(i);
}
cout << vint.get_size() << endl;
cout << vint[m] << endl;
vint.remove(m);
cout << vint.add(-1) << endl;
cout << vint[m] << endl;
Vector<int> vv = vint;
cout << vv[vv.get_size() - 1] << endl;
vv.add(m);
cout << vint.get_size() << endl;
cin >> n;
return 0;
}
输入:
100 50
输出:
100
50
99
51
-1
100
main()函数中,创建了一个int型的Vector对象vint,然后输入 n,m,向vint中添加0--n之间的自然数,索引和删除m位置的元素。
知识点学习:
T& operator[](int index) {
return data[index];
}
1.重载[]运算符来实现通过索引访问Vector中的元素
T&是一个引用类型,表示返回值的类型是一个T类型的引用。T可以是任意类型,取决于data数组的元素类型。通过返回T&,允许对data数组中指定索引的元素进行读写操作。
Vector&是一个返回引用的函数类型声明。在C++中,函数可以返回不同的值类型,包括基本数据类型、自定义类对象以及指针等。而返回引用的函数,实际上返回的是对象的引用,而不是对象的副本。
2.delete[] data;
delete[] data;是在C++中用于释放动态分配的数组内存的语句。
在C++中,可以使用new运算符来动态分配内存,而动态分配的内存需要手动释放,以防止内存泄漏。当我们使用new运算符分配一个数组时,需要使用delete[]运算符来释放该数组的内存。
delete[] data;表示释放指针变量data所指向的数组的内存。注意,delete[]运算符只能释放通过new[]运算符分配的数组内存,不能用于释放普通变量或通过new运算符分配的单个对象的内存。
在执行delete[] data;之后,data指针的值会变为一个未定义的值。这是因为delete[]运算符将释放指针所指向的内存,并且会使指针成为一个无效的指针。为了避免悬空指针的问题,建议在释放内存后将指针设置为nullptr,即data = nullptr;。这样可以避免在后续代码中误用已经释放的内存。
3.对象拷贝
Vector(const Vector<T>& other) {
size = other.size;
capacity = other.capacity;
data = new T[capacity];
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
拷贝构造函数
用于创建一个新的Vector对象,并将其初始化为另一个Vector对象other的副本。
在构造函数中,先将size和capacity成员变量赋值为other对应的值。然后,通过new关键字在堆上分配一个新的数组data,其大小为capacity。接下来,使用for循环将other的每个元素复制到新的数组中。
这样,就实现了一个新的Vector对象,它与other拥有相同的元素内容和大小。这个构造函数的目的是提供了一种方便的方式来创建一个与已有Vector对象相同的副本。
要使用这个拷贝构造函数,只需要在创建新的Vector对象时,将已有的Vector对象作为参数传递给构造函数即可。例如:
Vector<int> v1; // 创建一个空的Vector对象
// 假设已有一个Vector对象v2,包含一些元素
Vector<int> v2;
// 使用拷贝构造函数创建一个新的Vector对象v3,作为v2的副本
Vector<int> v3(v2);
拷贝运算符(对象默认含有)
可以使用等号运算符(=)来进行对象的赋值操作。当使用等号将一个对象赋值给另一个对象时,会调用拷贝赋值运算符(copy assignment operator),其实现方式与拷贝构造函数类似。
// 拷贝赋值运算符
Vector<T>& operator=(const Vector<T>& other) {
if (this != &other) {
delete[] data;
size = other.size;
capacity = other.capacity;
data = new T[capacity];
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
return *this;
}