1. 模板函数
template<class Type>
class SeqStack
{
private:
Type *data;
int size;
int top;
}
class String
{}
int main()
{
SeqStack<int> ist;
SeqStack<double> dst;
SeqStack<String> sst;
return 0;
}
总结
- 模板函数的格式要求:第一行需要添加:template,在使用模板函数时:SeqStack<数据类型> ist;
- 模板函数的作用:使得函数更具有通用性,Type表示使用模板函数的数据类型,如果是整型数据,则在函数中,Type类型的数据为整型数据,如果是double类型,Type类型的数据为double类型;
- 任何数据类型都可以使用模板函数,即使是自己定义的函数也可以作为类型使用模板函数;
- 在使用模板函数时,是对模板函数进行重命名,而不是宏替换。
//将SeqStack重命名为:
class SeqStack<int>
{
typedef int Type;
private:
Type *data;
int size;
int top;
}
2. 模板栈
在栈中,一般具有以下几个函数:
构造函数、析构函数、入栈、出栈、得到栈顶元素、判空、得到栈中元素
此模块为简单模板栈的编写:
template<class Type>
class SeqStack
{
private:
Type *data; //指向所存储的数据
int capacity;//栈容量
int pos; //栈顶
public:
SeqStack(int sz = 100):data(NULL),capacity(sz),pos(-1)//构造函数,初始化private成员
{
data = new Type[capacity];//通过new运算符申请空间,并调用构造函数;
}
void push(const Type &x)//入栈--改变对象状态,不能为常方法
{
data[++pos] = x;
}
void pop()//出栈--改变对象状态,不能为常方法
{
--pos;
}
Type & top()//得到栈顶元素
{
return data[pos];
}
const Type & top() const//得到栈顶元素
{
return data[pos];
}
bool empty() const//判空--不改变对象状态,常方法
{
return size() == 0;
}
size_t size() const//得到栈中元素--对象个数,不改变对象状态,常方法
{
return pos+1;
}
~SeqStack()//析构函数
{
delete []data;//释放空间
data = NULL;
capacity = 0;
pos = -1;
}
};
注意点
- size_t为无符号整型:unsigned int;
- 栈的容量和栈所含元素的个数是不同的概念;
- 成员方法和变量不能重命名;
- 两个得到栈顶元素函数的区别:
//例子:
class Object
{
private:
int value;
public:
Object(int x = 0):value(x){}
~Object() {}
//(1)int Value() { return value; }
//(2)int & Value() { return value; } ----第一个top
//改写为:int &Value(Object * const this)
//(3)int & Value() const { return value; } //常方法
//(4)----第二个top,常对象可以调用
const int & Value() const { return value; }
}
int main()
{
Object obj(100);
int x = obj.Value();
obj.Value() = 10; // 改写后:Value(&obj) = 10;
const Object obj2(10); //常对象
int y = obj2.Value();
}
(1)当Value()方法返回类型为int型时,则是以值的形式返回:返回时会创建临时空间,只具有可读性,不能被修改,因此:obj.Value() = 10,不能成功;
(2)当Value()方法返回类型为int & 型时,则是以引用形式返回:obj.Value() = 10;相当于obj.value = 10;可以修改value的值;
(3)int & Value() { return value; }改写为:int &Value(Object * const this) ,表示this不能改变,但this的指向可以被改变,常对象不能被改变,因此当常对象调用此方法时,产生矛盾,需要添加const,改为常方法;
(4)int & Value() const此方法返回的是引用–this->value,表示可以被改变,而常方法不能被改变,产生矛盾,因此在返回值类型需要添加const;
(5)普通对象优先选择普通方法,再选择常方法,而常对象只能选择常方法;
(6)当成员函数不改变对象的状态时,将其设置为常方法,使得方法通用性更强。
检验:
int main()
{
SeqStack<int> ist;
for(int i=0;i<10;i++)
{
ist.push(i+10);
}
int x=0;
while(!ist.empty())
{
x = ist.top();
ist.pop();
cout<<x<<endl;
}
return 0;
}
注意:
使用引用时可能会出现失效引用!!
下面进行举例说明:
//仍沿用上面模板
int main()
{
SeqStack<int> ist;
for(int i=0;i<10;i++)
{
ist.push(i+10);
}
while(!ist.empty())
{
int &a = ist.top();
ist.pop();
cout<<a<<endl;
}
return 0;
}
求问:a是否能够打印出?
在程序进行到调用ist.top()时,返回的是data[pos]本身,而a是data[pos]的引用,随后调用ist.pop()之后,pos-1,所以a指向的是pos-1的值,因而造成数据的丢失,形成失效引用。
本模块只是简单模板栈的编写,后续将会优化模板栈。