C++类模板
待更!
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; }