待更!
egg1
//
// stacktp.hpp
//
// Created by Min Zhu on 16/10/6.
// Copyright © 2016年 Min Zhu. All rights reserved.
//
#ifndef stacktp_hpp
#define stacktp_hpp
#include <stdio.h>
template <class Type>
class Stack {
private:
enum{MAX = 10}; // constant specific to class
Type items[MAX]; // holds stack items
int top; // index for top stack item
public:
Stack();
bool isempty();
bool isfull();
bool push(const Type & item); // add item to satck
bool pop(Type & item); // pop top into item
};
template <class Type>
Stack<Type>::Stack() {
top = 0;
};
template <class Type>
bool Stack<Type>::isempty(){
return top == 0;
}
template <class Type>
bool Stack<Type>::isfull(){
return top == MAX;
};
template <class Type>
bool Stack<Type>::push(const Type & item){
if(top < MAX){
items[top++] = item;
return true;
}
else
return false;
}
template <class Type>
bool Stack<Type>::pop(Type & item){
if(top > 0){
item = items[--top];
return true;
}
else
return false;
}
#endif /* stacktp_hpp */
//
// stacktp.cpp
//
// Created by Min Zhu on 16/10/6.
// Copyright © 2016年 Min Zhu. All rights reserved.
//
#include "stacktp.hpp"
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main(){
Stack<string> st; // create an empty stack
char ch;
string po;
cout << "Please enter A to add apurchase order,\n" << "P to process a PO, or Q to quit.\n";
while(cin >> ch && toupper(ch) != 'Q'){
while(cin.get() != '\n')
continue;
if(!isalpha(ch)){
cout << '\a';
continue;
}
switch (ch) {
case 'A':
case 'a':
cout << "Enter a PO number to add: ";
cin >> po;
if(st.isfull())
cout << "stack already full\n";
else
st.push(po);
break;
case 'P':
case 'p':
if(st.isempty())
cout << "stack already empty\n";
else{
st.pop(po);
cout << "PO #" << po << " popped\n";
break;
}
}
cout << "Please enter A to add a purchase order,\n" << "P to process a PO, or Q to quit.\n";
}
cout << "Bye\n";
return 0;
}
运行结果(Xcode):
Please enter A to add apurchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: red911porsche
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: blueR8audi
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
A
Enter a PO number to add: silver747boeing
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #silver747boeing popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #blueR8audi popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
PO #red911porsche popped
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
P
stack already empty
Please enter A to add a purchase order,
P to process a PO, or Q to quit.
Q
Bye
Program ended with exit code: 0
深入探讨模板类
可以使用char指针替换上面程序中的string对象吗?毕竟,这种指针是处理c风格字符串的内置方式。答案是可以创建指针栈,不过必须对程序包进行重大修改。
1.不正确地使用指针栈
设计模板时应牢记一些教训,切忌盲目使用模板。以下列举3个试图对上面程序eg1进行修改,使之使用指针栈的简单(但有缺陷的)示例。它们都以完全正确的Stack<Type>模板为基础:Stack<char *> st;
版本1,将eg1中的string po;替换为char * po;
目的是用char指针而不是string对象来接收键盘输入。这种方法是失败的:因为仅仅创建指针而没有创建用于保存输入字符串的空间(程序将通过编译,但在cin试图将输入保存在某些不合适的内存单元中时崩溃)
版本2,将string po;替换为char po[40];
这为输入的字符串分配了空间。另外,po的类型为char *,因此可以放在栈中,不过数组与pop()方法的假设相冲突:
template <class Type>
bool Stack<Type>::pop(Type & item){
if(top > 0){
item = items[--top];
return true;
}
else
return false;
}
首先,引用变量必须引用某种类型的左值,而不是数组名。其次,代码假设可以给item赋值,即使item能够引用数组,也不能为数组名赋值。故此法失效。
版本3,将string po;替换为char * po = new char[40];
这为输入的字符串分配了空间。另外,po的类型为变量,因此与pop()的代码兼容。然而问题是:只有一个pop变量,它总是指向相同的内存单元。在每当读取新字符串时,内存的内容都将发生改变,而每次执行压入操作时,加入到栈中的地址都相同。则对栈执行弹出操作时,得到的地址总是相同的,它总是指向读入的最后一个字符串。具体就是栈并未保存每一个新字符串,因而没有什么用途。
2.正确地使用指针栈
使用指针栈的方法之一是,让调用程序提供一个指针数组,其中每个指针指向不同的字符串。栈的任务是管理指针,而不是创建指针。
//stcktp1.h -- modified Stack template
#ifndef STCKTP1_H_
#define STCKTP1_H_
template <class Type>
class Stack{
private:
enum {SIZE = 10};
int stacksize;
Type * items;
int top;
public:
explicit Stack(int ss = SIZE);
Stack(const Stack & st);
~Stack(){
delete[] items;
}
bool isempty(){
return top == 0;
}
bool isfull(){
return top == stacksize;
}
bool push(const Type & item); // add item to stack
bool pop(Type & item); // pop top into item
Stack & operator=(const Stack & st);
};
template <class Type>
Stack<Type>::Stack(int ss) :stacksize(ss), top(0){
items = new Type [stacksize];
}
template <class Type>
Stack<Type>::Stack(const Stack & st){
stacksize = st.stacksize;
top = st.top;
items = new Type [stacksize];
for (int i = 0; i < top; i++){
items[i] = st.items[i];
}
}
template <class Type>
bool Stack<Type>::push(const Type & item){
if (top < stacksize){
items[top++] = item;
return true;
}
else
return false;
}
template <class Type>
bool Stack<Type>::pop(Type & item){
if (top > 0){
item = items[--top];
return true;
}
else
return false;
}
template <class Type>
Stack<Type> & Stack<Type>::operator=(const Stack<Type> & st){
if (this == &st)
return *this;
delete [] items;
stacksize = st.stacksize;
top = st.top;
items = new Type [stacksize];
for (int i = 0;i< top; i++) {
items[i] = st.items[i];
}
return *this;
}
#endif
#include <iostream>
#include <cstdlib> // for rand().srand()
#include <ctime> // for time()
#include "stcktp1.h"
using namespace std;
const int Num = 10;
int main(){
srand(time(0)); //randomize rand()
cout << "Please enter stack size:";
int stacksize;
cin >> stacksize;
//create an empty stack with stacksize slots
Stack<const char *> st(stacksize);
//in basket
const char * in[Num] = {
" 1: Hank Gilgamesh", " 2: Kiki Ishatar",
" 3: Betty Rocker", " 4: Ian Flagrant",
" 5: Wolfgang Kibble", " 6: Portia koop",
" 7: Joy Almondo", " 8: Xaverie Paprika",
" 9: Juan Moore", "10: Misha Mache"
};
//out basket
const char * out[Num];
int processed = 0;
int nextin = 0;
while (processed < Num){
if (st.isempty())
st.push(in[nextin++]);
else if (st.isfull())
st.pop(out[processed++]);
else if (rand() % 2 && nextin < Num)
st.push(in[nextin++]);
else
st.pop(out[processed++]);
}
for (int i = 0; i < Num; i++){
cout << out[i] << endl;
}
cout << "Bye\n";
return 0;
}