此例C++的堆栈实现与之前C的堆栈实现相比的优点及自身特点:
1、良好的封装性和安全性,这也是C++语言本身具有的特点,在C实现的栈的方法中,需要判断入参栈指针合法性,而C++中无需,因为栈指针是成员变量,不是显式入参,不会勿传其他指针。比如销毁堆栈时,C++可以利用析构函数,无需判断堆栈指针S是否为NULL,而若C代码实现销毁,则需要一段判断堆栈指针S是否为NULL的代码,否则后续代码执行会发生异常;又如清空堆栈函数,在C++中无需判断S指针是否存在,因为要调用这个清空函数,堆栈类必须先已经实例化了,这就保证了调用清空函数前S已经存在并有所指向,而C中则S指针是否存在得在清空函数中进行判断,排除S指针不存在的情况及S指针为野指针的情况才能进行后续操作。所以说C++的封装性具有良好的安全性。
2、实例初始化自动调用构造函数,销毁自动调用析构函数,而不用像C语言实现里需要显式调用,增加代码量,易忘销毁内存而造成内存泄露。
3、类的方法调用本类的方法可以不像其他域中用"实例.方法"来调用来的复杂,因为隐含this指针,比如本例中m_Stack.Run()里调用Push(),若在main函数里调用则是Stack m_Stack; m_Stack.Push(X)。所以建议不要再main里写“实例.方法”等细的模块功能操作。面向对象的编程应该是立即把main函数转入某一个类实例化的方法中,然后由这个实例的方法进行环境初始化,实例化其他类,进行各种操作。main相当于一个入口地址,立即跳转,然后不再使用。
4、另外特别要注意堆栈实例进行拷贝时,默认拷贝构造函数(赋值构造函数)具有局限性,必要得自己重写。
以下是使用默认赋值构造函数的运行结果:
可以看出m_Stack的指针指向了s_Stack指针指向的内存区,以致后来s_Stack的压栈影响了m_Stack的堆栈情况,另外m_Stack的指针原先指向的内存并没有释放,所以既不符合实际想要结果,又非法。
这时就实现了我们本来想要的结果,即堆栈的内容进行拷贝。
完整代码如下:
/*
============================================================================
Name : 堆栈(堆栈,堆栈,堆中开的栈空间,所以叫堆栈)
Author : Swair Fang
Version : 1.1
Copyright : by Swair Fang
Description : 堆栈实现, Ansi-style
功能:
1.压栈
2.出栈
3.查看栈顶
4.打印栈
============================================================================
*/
#include
#include
#include
using namespace std;
#ifndef _Stack_H
#define _Stack_H
typedef int ElementType;
//构建节点
typedef struct Node
{
ElementType Element;
struct Node *Next;
};
//构建堆栈
class Stack
{
private:
struct Node *S;
struct Node *P;
public:
Stack();
~Stack();
void operator=(Stack &right);
void Push(ElementType X);
void Pop(ElementType *pX);
void Top(ElementType *pX);
void MakeEmpty();
void Print();
void Run();
void Empty();
};
Stack::Stack()
{
printf("Create Stack\n");
S=new Node;
if(S==NULL)
printf("Out of space!!!");
S->Next=NULL;
}
Stack::~Stack()
{
printf("Destroy Stack\n");
if(S==NULL)
printf("Must use CreateStack first");
else
{
Node *Tmp;
P=S->Next;
S->Next=NULL;
while(P!=NULL)
{
Tmp=P->Next;
delete P;
P=Tmp;
}
delete S;
}
}
void Stack::Empty()
{
printf("Empty Stack\n");
if(S==NULL)
printf("Must use CreateStack first");
else
{
Node *Tmp;
P=S->Next;
S->Next=NULL;
while(P!=NULL)
{
Tmp=P->Next;
delete P;
P=Tmp;
}
}
}
//由于默认的赋值构造函数是完全赋值,即本实例的变量数值会被另一个实例的变量数值完全取代,
//特别是指针,也就是说本实例的指针值等于另一实例的指针值,即两指针指向了同一块内存,
//而被赋值的实例的指针指向的内存并没有释放,这就会引起问题,所以得自己写赋值构造函数
//使得实例之间的赋值为实际意义的变量内容的赋值,而非完全赋值。
void Stack::operator=(Stack &right)
{
printf("call assignment\n");
Empty();
P=S;
right.P=right.S->Next;
while(right.P!=NULL)
{
struct Node *Tmp=new Node;
Tmp->Element=right.P->Element;
Tmp->Next=NULL;
P->Next=Tmp;
P=P->Next;
right.P=right.P->Next;
}
}
//1.压栈
void Stack::Push(ElementType X)
{
P=new Node;
if(P==NULL)
{
printf("Out of space!!!");
exit(1);
}
P->Element=X;
P->Next=S->Next;
S->Next=P;
}
//2.出栈
void Stack::Pop(ElementType *pX)
{
if(S==NULL||S->Next==NULL)
printf("Empty stack");
else
{
P=S->Next;
S->Next=S->Next->Next;
ElementType X=P->Element;
free(P);
*pX=X;
}
}
//3.查看栈顶
void Stack::Top(ElementType *pX)
{
if(S==NULL||S->Next==NULL)
printf("Empty stack");
else
{
*pX=S->Next->Element;
}
}
//4.打印栈
void Stack::Print()
{
if(S->Next==NULL)
printf("链表为空\n");
else
{
P=S->Next;
while(P!=NULL)
{
char *cp=(char*)P;
printf("0x%x: %d\n ",cp,P->Element);
P=P->Next;
}
printf("\n");
}
}
void Stack::Run()
{
Stack m_Stack;
Push(3);
Push(23);
Push(33);
m_Stack.Push(63);
m_Stack.Push(61);
printf("\ns_Stack情况:\n");
Print();
printf("m_Stack情况:\n");
m_Stack.Print();
printf("\nm_Stack拷贝给s_Stack:\n");
*this=m_Stack;
printf("\ns_Stack情况:\n");
Print();
printf("m_Stack情况:\n");
m_Stack.Print();
printf("m_Stack压栈\n");
m_Stack.Push(333);
m_Stack.Push(424);
m_Stack.Push(32);
m_Stack.Push(12);
m_Stack.Push(53);
m_Stack.Push(123);
printf("\ns_Stack情况:\n");
Print();
printf("m_Stack情况:\n");
m_Stack.Print();
}
#endif/*_Stack_H*/
class MAINServer
{
public:
void Start();
};
void MAINServer::Start()
{
Stack m_Stack;
Stack s_Stack;
m_Stack.Push(3);
m_Stack.Push(23);
m_Stack.Push(33);
s_Stack.Push(63);
s_Stack.Push(61);
printf("\nm_Stack情况:\n");
m_Stack.Print();
printf("s_Stack情况:\n");
s_Stack.Print();
printf("\ns_Stack拷贝给m_Stack:\n");
m_Stack=s_Stack;
printf("\nm_Stack情况:\n");
m_Stack.Print();
printf("s_Stack情况:\n");
s_Stack.Print();
printf("s_Stack压栈\n");
s_Stack.Push(333);
printf("\nm_Stack情况:\n");
m_Stack.Print();
printf("s_Stack情况:\n");
s_Stack.Print();
printf("--------------\n");
s_Stack.Run();
}
int main()
{
MAINServer MS;
MS.Start();
cout << "Hello World!!!" << endl; // prints Hello World!!!
return 0;
}