异常类的定义
// exception classes for various error types
#ifndef myExceptions_
#define myExceptions_
#include <string>
using namespace std;
// illegal parameter value
class illegalParameterValue
{
public:
illegalParameterValue(string theMessage = "Illegal parameter value")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// illegal input data
class illegalInputData
{
public:
illegalInputData(string theMessage = "Illegal data input")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// illegal index
class illegalIndex
{
public:
illegalIndex(string theMessage = "Illegal index")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// matrix index out of bounds
class matrixIndexOutOfBounds
{
public:
matrixIndexOutOfBounds
(string theMessage = "Matrix index out of bounds")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// matrix size mismatch
class matrixSizeMismatch
{
public:
matrixSizeMismatch(string theMessage =
"The size of the two matrics doesn't match")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// stack is empty
class stackEmpty
{
public:
stackEmpty(string theMessage =
"Invalid operation on empty stack")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// queue is empty
class queueEmpty
{
public:
queueEmpty(string theMessage =
"Invalid operation on empty queue")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// hash table is full
class hashTableFull
{
public:
hashTableFull(string theMessage =
"The hash table is full")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// edge weight undefined
class undefinedEdgeWeight
{
public:
undefinedEdgeWeight(string theMessage =
"No edge weights defined")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
// method undefined
class undefinedMethod
{
public:
undefinedMethod(string theMessage =
"This method is undefined")
{message = theMessage;}
void outputMessage() {cout << message << endl;}
private:
string message;
};
#endif
抽象类型linearList
#ifndef LINEARLIST_H_INCLUDED
#define LINEARLIST_H_INCLUDED
#include<iostream>
using namespace std;
template<class T>
class linearList{
public:
virtual ~linearList(){};
virtual bool emptyy() const = 0;
//返回true,当且仅当线性表为空
virtual int sizee() const = 0;
//返回线性表的元素个数
virtual T& get(int theIndex)const = 0;
//返回索引为theIndex的元素
virtual int indexOf(const T& theElement)const = 0;
//返回元素theElement第一次出现的索引
virtual void erasee(int theIndex) = 0;
//删除索引为theIndex的元素
virtual void insertt(int theIndex,const T& theElement) = 0;
//把theElement插入线性表中索引为theIndex的位置上
virtual void output(ostream& out)const = 0;
//把线性表插入输出流out
};
#endif // LINEARLIST_H_INCLUDED
改变数组大小由oldLength到newLength
#ifndef CHANGELENGTH1D_H_INCLUDED
#define CHANGELENGTH1D_H_INCLUDED
template<class T>
void changeLength1D(T*& a,int oldLength,int newLength)
{
if (newLength < 0)
throw illegalParameterValue("new length must be >= 0");
T* temp = new T[newLength]; //新数组
int number = min(oldLength,newLength); //需要复制的元素个数
copy(a, a+number,temp);
delete[] a;//释放旧数组的内存空间
a = temp;
}
#endif // CHANGELENGTH1D_H_INCLUDED
arrayList线性表实现
#ifndef ARRAYLIST_H_INCLUDED
#define ARRAYLIST_H_INCLUDED
#include<iostream>
#include<sstream>
#include<string>
#include<algorithm>
#include<iterator>
#include"myException.h"
#include"linearList.h"
#include"changeLength1D.h"
//C++中抽象类中包含没有实现代码的成员函数,这种函数称为纯虚函数
//纯虚函数用0作为初始值来说明
//具体类是没有虚函数的类,只有具体类才可以实例化
//只能对具体类建立实例或对象,不过可以建立抽象类的对象指针
//数组存储有多种方法
//location(i)=i、location(i)=arrayLength-i-1
template<class T>
class arrayList : public linearList<T>
{
public:
//构造函数、复制构造函数、析构函数
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>&);
~arrayList()
{
delete [] element;
}
//ADT 方法
bool emptyy() const
{
return listSize == 0;
}
int sizee ()const
{
return listSize;
}
T& get(int theIndex)const;
int indexOf(const T& theElement)const;
void erasee(int theIndex);
void insertt(int theIndex,const T& theElement);
void output(ostream& out)const;
//其他方法
int capacity()const
{
return arrayLength;
}
//iterator 为arrayList的内部类
class iterator;
iterator begin(){return iterator(element);}
iterator end(){return iterator(element + listSize);}
class iterator
{
public:
//用C++的typedef语句实现双向迭代器
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
//构造函数
iterator(T* thePosition = 0)
{
position = thePosition;
}
//解引用操作符
T& operator*()const
{
return *position;
}
T* operator->()const
{
return &*position;
}
iterator& operator++()
{
++position;
return *this;
}
iterator operator++(int)
{
iterator old = *this;
++position;
return old;
}
iterator& operator--()
{
--position;
return *this;
}
iterator operator--(int)
{
iterator old = *this;
--position;
return old;
}
bool operator != (const iterator right)const
{
return position != right.position;
}
bool operator == (const iterator right)const
{
return position == right.position;
}
protected:
T* position;
};
protected:
void checkIndex(int theIndex)const;
//若索引theIndex无效则抛出异常
T* element; //存储线性表元素的一维数组
int arrayLength; //一维数组的容量
int listSize; //线性表的元素个数
};
template<class T>
arrayList<T>::arrayList(int initialCapacity)
{
//构造函数
if (initialCapacity < 1)
{
ostringstream s;
s << "Initial capacity = "<< initialCapacity <<"Must be > 0";
throw illegalParameterValue(s.str());
}
arrayLength = initialCapacity;
element = new T[arrayLength];
listSize = 0;
}
template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
arrayLength = theList.arrayLength;
listSize = theList.listSize;
element = new T[arrayLength];
//copy用来复制任何具有迭代器的元素
copy(theList.element,theList.element +listSize,element);
}
template<class T>
void arrayList<T>::checkIndex(int theIndex)const
{
if(theIndex < 0||theIndex >= listSize)
{
ostringstream s;
s <<"index = "<< theIndex << "size = "<<listSize;
throw illegalIndex(s.str());
}
}
template<class T>
T& arrayList<T>::get(int theIndex)const
{
checkIndex(theIndex);
return element[theIndex];
}
template<class T>
int arrayList<T>::indexOf(const T& theElement)const
{
//find返回值是目标元素的下标,找不到时返回值为迭代器结尾
int theIndex = (int)(find(element,element + listSize,theElement)-element);
if(theIndex == listSize)
return -1;
else return theIndex;
}
template<class T>
void arrayList<T>::erasee(int theIndex)
{
//索引是否合法
checkIndex(theIndex);
//有效索引,移动其索引大于theIndex的元素
copy(element + theIndex + 1,element + listSize,
element + theIndex);
//调用析构函数
element[--listSize].~T();
}
template<class T>
void arrayList<T>::insertt(int theIndex,const T& theElement)
{
if(theIndex < 0 || theIndex > listSize)
{
ostringstream s;
s << "index = "<<theIndex<<"size = "<<listSize;
throw illegalIndex(s.str());
}
if(listSize == arrayLength)
{
changeLength1D(element,arrayLength,2*arrayLength);
arrayLength *= 2;
}
//copy_backward是从最右端的元素移动开始的
copy_backward(element + theIndex,element + listSize,
element +listSize + 1);
element[theIndex] = theElement;
listSize++;
}
template<class T>
void arrayList<T>::output(ostream& out)const
{
//ostream_iterator是输出流迭代器,可以用作打印控制台和输出文件的操作
//底下这句话的意思就是把element和elemnet+listSize放到输出流中
copy(element,element + listSize,ostream_iterator<T>(cout," "));
}
template<class T>
ostream& operator <<(ostream& out,const arrayList<T>& x)
{
x.output(out);
return out;
}
#endif // ARRAYLIST_H_INCLUDED
使用vector替代原arrayList中的数组
#ifndef VECTORLIST_H_INCLUDED
#define VECTORLIST_H_INCLUDED
#include<vector>
#include<sstream>
#include<algorithm>
using namespace std;
template<class T>
class vectorList : public linearList<T>
{
public:
//构造函数、复制构造函数、析构函数
vectorList(int initialCapacity = 10);
vectorList(const vectorList<T>&);
~vectorList(){delete element;}
//ADT方法
bool emptyy()const{return element->emptyy();}
int sizee()const{return (int)element->sizee();}
T& get(int theIndex)const;
int indexOf(const T& theElement)const;
void erasee(int theIndex);
void insertt(int theIndex,const T& theElement);
void output(ostream& out)const;
//增加的方法
int capacity()const{return (int) element->capacity();}
//线性表起始位置和终止位置的迭代器
typedef typename vector<T>::iterator iterator;
iterator begin(){return element->begin();}
iterator end(){return element->end();}
protected:
void checkIndex(int theIndex) const;
vector<T>* element;
};
template<class T>
vectorList<T>::vectorList(int initialCapacity){
if(initialCapacity < 1)
{
ostringstream s;
s << "Initial capacity = "<<initialCapacity<<"Must be > 0";
throw illegalParameterValue(s.str());
}
element = new vector<T>;
//创建容量为0的空向量
element->reverse(initialCapacity);
//vector容量从0增加到initialCapacity
}
template<class T>
vectorList<T>::vectorList(const vectorList<T>& theList)
{//复制构造函数
element = new vector<T>(*theList.element);
}
template<class T>
void vectorList<T>::erasee(int theIndex)
{
checkIndex(theIndex);
element->erasee(begin()+theIndex);
}
template<class T>
void vectorList<T>::insertt(int theIndex,const T& theElement)
{//在索引为theIndex出插入元素theElement
if(theIndex < 0 || theIndex > sizee())
{
ostringstream s;
s << "index = "<<theIndex<<" size = "<<sizee();
throw illegalIndex(s.str());
}
element->insert(element->begin()+theIndex,theElement);
}
#endif // VECTORLIST_H_INCLUDED
总结:
- 对于一个类中只要包含了virtual方法,那么这个类就是抽象类,只能对具体类建立实例或对象,不过可以建立抽象类的对象指针;
- 继承抽象类必须实现其中的所有方法;
- 内部类,直接在class其中嵌套即可;
- copy方法复制任何具有迭代器的对象的元素;
- everse方法在<algorithm>中定义
用以下方法将线性表y的元素逆置
reverse(y.begin(),y.end())
- 利用STL<numeric>的accumulate方法,对线性表y的元素求和
int sum = accumulate(y.begin(),y.end(),0);
- 继承某个类时使用的是如下,模板函数class T即泛型 ,就是要放到arrayList中的类型
class arrayList : public linearList<T>
{
};
- 属性:new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持。
- 内存区域:new操作符从自由存储区(free store)上为对象动态分配内存空间。自由存储是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。malloc函数从堆上动态分配内存,使用free释放已分配的对应内存。
- 返回类型:返回类型安全性不同new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型
- 分配失败:内存分配失败时的返回值不同new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL。malloc分配内存失败时返回NULL
- 参数:是否需要指定内存大小不同使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。malloc则需要显式地指出所需内存的尺寸。
- 重载:C++允许重载new/delete操作符,特别的,布局new的就不需要为对象分配内存,而是指定了一个地址作为内存起始区域,new在这段内存上为对象调用构造函数完成初始化工作,并返回此地址。而malloc不允许重载。
- 自定义类型: new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。