课程目标
- 完成 StaticList 类的具体实现
- 完成 DynamicList 类的具体实现
StaticList 设计要点
类模板
- 使用原生数组作为顺序存储空间
- 使用模板参数决定数组大小
template <typename T, int N>
class StaticList : public SeqList<T>
{
public:
StaticList(); // 指定父类成员的具体值
int capacity() const;
protected:
T m_space[N]; // 顺序存储空间,N为模板参数
};
编程实验:StaticList 的实现
文件:StaticList.h
#ifndef STATICLIST_H
#define STATICLIST_H
#include "SqlList.h"
namespace DTLib
{
template <typename T, int N>
class StaticList : public SqlList<T>
{
public:
StaticList()
{
this->m_array = m_space;
this->m_length = 0;
}
int capacity() const override
{
return N;
}
protected:
T m_space[N];
};
}
#endif // STATICLIST_H
文件:main.cpp
#include <iostream>
#include "StaticList.h"
using namespace std;
using namespace DTLib;
int main()
{
cout << "main begin" << endl;
StaticList<int, 5> sl;
for (int i = 0; i < sl.capacity(); ++i)
{
sl.insert(0, i);
}
for (int i = 0; i< sl.length(); ++i)
{
cout << sl[i] << endl;
}
cout << "--------------" << endl;
sl[0] *= sl[0];
for (int i = 0; i< sl.length(); ++i)
{
cout << sl[i] << endl;
}
cout << "--------------" << endl;
try
{
sl[5] = 5;
}
catch (const Exception &e)
{
cout << e.message() << endl;
cout << e.location() << endl;
}
cout << "main end" << endl;
return 0;
}
输出:
main begin
4
3
2
1
0
--------------
16
3
2
1
0
--------------
Parameter i is invalid ...
..\DTLib\SqlList.h:92
main end
DynamicList 设计要点
类模板
- 申请连续堆空间作为顺序存储空间
- 动态设置顺寻存储空间的大小
- 保证重置顺序存储空间时的异常安全性
函数异常安全的概念
- 不泄露任何资源
- 不允许破坏数据
函数异常安全的基本保证
如果异常被抛出
- 对象内的任何成员仍然能保持有效状态
- 没有数据的破坏及资源泄漏
template <typename T>
class DynamicList : public SqlList<T>
{
public:
DynamicList(int capacity) // 申请空间
int capacity() const;
void resize(int capacity); // 重新设置存储空间的大小
~DynamicList(); // 归还空间
protected:
int m_capacity; // 顺序存储空间的大小
};
编程实验:DynamicList 的实现
文件:DynamicList.h
#ifndef DYNAMICLIST_H
#define DYNAMICLIST_H
#include "SqlList.h"
#include "Exception.h"
namespace DTLib
{
template <typename T>
class DynamicList : public SqlList<T>
{
public:
DynamicList(int capacity)
{
this->m_array = new T[capacity];
if (this->m_array != nullptr)
{
this->m_capacity = capacity;
this->m_length = 0;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create DynamicList object ...");
}
}
int capacity() const override
{
return m_capacity;
}
void resize(int capacity)
{
if (capacity != m_capacity)
{
T *array = new T[capacity]; // 注意 1
if (array != nullptr)
{
int length = (this->m_length < capacity) ? this->m_length : capacity;
for (int i = 0; i< length; ++i)
{
array[i] = this->m_array[i]; // 注意 2
}
T *temp = this->m_array; // 注意 3
this->m_array = array;
this->m_length = length;
this->m_capacity = capacity;
delete [] temp; // 注意 3
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No meomry to resize DynamicList object ...");
}
}
}
~DynamicList()
{
delete [] this->m_array;
}
protected:
int m_capacity = 0;
};
}
#endif // DYNAMICLIST_H
文件:main.cpp
#include <iostream>
#include "DynamicList.h"
using namespace std;
using namespace DTLib;
int main()
{
cout << "main begin" << endl;
DynamicList<int> sl(5);
for (int i = 0; i < sl.capacity(); ++i)
{
sl.insert(0, i);
}
for (int i = 0; i< sl.length(); ++i)
{
cout << sl[i] << endl;
}
cout << "--------------" << endl;
sl[0] *= sl[0];
for (int i = 0; i< sl.length(); ++i)
{
cout << sl[i] << endl;
}
cout << "--------------" << endl;
try
{
sl[5] = 5;
}
catch (const Exception &e)
{
cout << e.message() << endl;
cout << e.location() << endl;
sl.resize(10);
sl.insert(5, 50);
}
for (int i = 0; i< sl.length(); ++i)
{
cout << sl[i] << endl;
}
cout << "--------------" << endl;
sl.resize(3);
for (int i = 0; i< sl.length(); ++i)
{
cout << sl[i] << endl;
}
cout << "main end" << endl;
return 0;
}
输出:
main begin
4
3
2
1
0
--------------
16
3
2
1
0
--------------
Parameter i is invalid ...
..\DTLib\SqlList.h:92
16
3
2
1
0
50
--------------
16
3
2
main end
注意 1:T *array = new T[capacity];
申请新的内存空间,对原内存空间中的数据进行拷贝,以保留原始值。
注意 2:array[i] = this->m_array[i];
T 为泛指类型,因此拷贝赋值操作符可能被重载并抛出异常;
当异常发生时,函数执行停止并返回,此时当前类的数据成员(m_array,m_length,m_capacity)未被破坏,线性表仍然合法有效;
会造成 array 指向的内存空间泄漏,交由使用者负责。
注意 3:T *temp = this->m_array;
当不借助临时指针变量时:
delete this->m_array; // 注意
this->m_array = array;
this->m_length = length;
this->m_capacity = capacity;
T 为泛指类型,因此析构函数中可能抛出异常;
当异常发生时,函数执行停止并返回,此时当前类的数据成员(m_array,m_length,m_capacity)未被修改,依然保持原始值,但此时m_array指向的内容可能已发生改变,线性表不再合法;
为解决以上问题,引入临时指针变量,当类中数据成员全部完成状态更新后,再 delete 临时变量指向的内存空间。
问题:是否可以将 DynamicList 作为 StaticList 的子类实现?
不可以,反之也不可以;
两个类对于对于顺序存储空间的指定没有任何关系,因此在类层次中位于同一层。
小结
- StaticList 通过模板参数定义顺序存储空间
- DynamicList 通过动态内存申请定义顺序存储空间
- Dyanmic 支持动态重置顺序存储空间的大小
- DynamicList 中的 resize() 函数实现需要保证异常安全
以上内容整理于狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。