初次尝试了c++类模板,来完成顺序表
//.h文件
template <typename T>
class SeqList {
private:
T* arr;
int capacity;
int size;
public:
SeqList();
SeqList(T* arr, int size);
SeqList(const SeqList<T>& sl);
~SeqList();
void PushBack(T data); //尾插
void PopBack(); //尾删
void PushFront(T data); //头插
void PopFront(); //头删
void Insert(int pos, T data); //任意位置插入
void Erase(int pos); //任意位置删除
bool Empty(); //检测顺序表是否为空
bool Find(T data); //检测data是否在顺序表中
void Remove(T data); //移除顺序表中第一个值为data的元素
void RemoveAll(T data); //移除顺序表中所有值为data的元素
int getSize() { //获取顺序表有效元素个数
return size;
}
int getCapacity() { //获取顺序表的容量
return capacity;
}
T getFront() { //获取顺序表中第一个元素
return arr[0];
}
T getBack() { //获取顺序表中最后一个元素
return arr[size - 1];
}
SeqList& operator=(const SeqList& sl);
T& operator[](int i);
template<typename T>
friend std::ostream& operator<<(std::ostream& os, const SeqList<T>& sl);
};
- 遇到的第一个问题,就是默认构造函数和析构函数报错:error LNK2019: 无法解析的外部符号 “public: void __thiscall…
原因是类模板的.cpp文件链接时出了问题,具体原因这里就不讲了,感兴趣可以自行查找,在网上找到的解决方法有两种
1.使用export关键字,但我使用无果后查找原因,这个关键字vs和gcc都不支持,这个功能在c++17就移除了,现在关键字还保留着,今后可能会赋予新的功能。
2.另一种解决思路有多种方法,可以将类函数的实现和类声明一起写在.h文件中,或者.h和.cpp分开写,在.h的声明后面加上#include”.cpp" ,还可以选择在使用类模板的文件中#include".cpp"
//.cpp文件
//默认构造函数
template<typename T>
SeqList<T>::SeqList() {
arr = new T[10];
size = 0;
capacity = 10;
}
template<typename T>
SeqList<T>::SeqList(T * arr, int size) {
this->arr = new T[size];
this->size = size;
this->capacity = 2 * size;
for (int i = 0; i < size; ++i) {
this->arr[i] = arr[i];
}
}
//复制构造函数
template<typename T>
SeqList<T>::SeqList(const SeqList<T>& sl) {
this->arr = new T[sl.capacity];
this->size = sl.size;
this->capacity = sl.capacity;
for (int i = 0; i < sl.size; ++i) {
this->arr[i] = sl.arr[i];
}
}
//析构函数
template<typename T>
SeqList<T>::~SeqList() {
delete[] arr;
}
//然后是顺序表的一些功能实现,较为简短的已经在声明中隐式内联实现了
template<typename T>
void SeqList<T>::PushBack(T data) {
if (size == capacity) {
T* tmp = arr;
arr = new T[capacity * 2];
capacity *= 2;
for (int i = 0; i < size; ++i) {
arr[i] = tmp[i];
}
delete[] tmp;
}
arr[size] = data;
++size;
}
template<typename T>
void SeqList<T>::PopBack() {
--size;
}
template<typename T>
void SeqList<T>::PushFront(T data) {
if (size == capacity) {
T* tmp = arr;
arr = new T[capacity * 2];
capacity *= 2;
for (int i = 0; i < size; ++i) {
arr[i] = tmp[i];
}
delete[] tmp;
}
for (int i = size; i > 0; --i) {
arr[i] = arr[i - 1];
}
arr[0] = data;
++size;
}
template<typename T>
void SeqList<T>::PopFront() {
for (int i = 0; i < size - 1; ++i) {
arr[i] = arr[i + 1];
}
--size;
}
//添加元素时的动态扩容也可以封装成一个private成员函数,使代码更简洁
template<typename T>
void SeqList<T>::Insert(int pos, T data) {
if (size == capacity) {
T* tmp = arr;
arr = new T[capacity * 2];
capacity *= 2;
for (int i = 0; i < size; ++i) {
arr[i] = tmp[i];
}
delete[] tmp;
}
if (pos >= size || pos < 0) {
arr[size] = data;
}
else {
for (int i = size; i > pos; --i) {
arr[i] = arr[i - 1];
}
arr[pos] = data;
}
++size;
}
template<typename T>
void SeqList<T>::Erase(int pos) {
if (pos >= 0 && pos < size) {
for (int i = pos; i < size - 1; ++i) {
arr[i] = arr[i + 1];
}
--size;
}
}
bool SeqList<T>::Empty() {
if (size == 0) {
return true;
}
else {
return false;
}
}
template<typename T>
bool SeqList<T>::Find(T data) {
for (int i = 0; i < size; ++i) {
if (arr[i] == data) {
return true;
}
}
return false;
}
template<typename T>
void SeqL/ist<T>::Remove(T data) {
for (int i = 0; i < size; ++i) {
if (arr[i] = data) {
Erase(i);
return;
}
}
}
template<typename T>
void SeqList<T>::RemoveAll(T data) {
for (int i = 0; i < size; ++i) {
if (arr[i] == data) {
Erase(i);
continue;
}
}
}
//这里一定要定义自己的赋值运算符重载函数,否则默认生成的复制函数只会复制成员的值,
//使两个对象中的指针指向同一块内存空间,当一个对象析构后,另一个析构时就会重复delete一段空间第二次
template<typename T>
SeqList<T>& SeqList<T>::operator=(const SeqList<T>& sl) {
if (this != &sl) {
delete[] this->arr;
this->arr = new T[sl.capacity];
this->size = sl.size;
this->capacity = sl.capacity;
for (int i = 0; i < sl.size; ++i) {
this-/>arr[i] = sl.arr[i];
}
}
return *this;
}
//重载 [ ] 让顺序表使用更加方便
template<typename T>
T & SeqList<T>::operator[](int i) {
return this->arr[i];
}
//用于cout的<<需要重载为友元函数才能按下面的顺序接受参数从而实现连续输出,但类模板的友元函数需要在声明时加上template<typename T>,
//否则无法与类一同成为模板。因为它不是类的成员却要使用const SeqList<T> & sl 为参数,编译器不知道<T>到底该是什么
template<typename T>
std::ostream & operator<<(std::ostream & os, const SeqList<T> & sl) {
for (int i = 0; i < sl.size; ++i) {
os << sl.arr[i] << " ";
}
return os;
}
如有问题欢迎留言指出。