By Brian Fitzgerald
The C++ “>>” (extraction operator) and “<<” (insertion operator) are normally used with I/O streams (cin/cout), but you can overload these operators in your own classes and make them do other things. In this case, I implement a stack of integers. “>>” is used for push and “<<” is used for pop. Here is Stk.cpp, containing the Stk class routines:
#include "Stk.h"
// push i onto the stack
Stk& operator >>(Stk& st, int i) {
st.ints = (int *) realloc(st.ints, (++st.len * sizeof(int)));
st.ints[st.len - 1] = i;
return st;
}
// pop i off the stack
Stk& operator <<(Stk& st, int &i) {
if (st.len == 0) {
throw "empty stack";
}
i = st.ints[--st.len];
return st;
}
int Stk::size() {
return len;
}
int Stk::peek() {
return ints[len - 1];
}
bool Stk::isempty() {
return len == 0;
}
A few things to notice:
- The stack is implemented as ints, an array of int.
- Push resizes the array with a call to realloc.
- Operators >> and << are not members of class Stk
- They are implemented as friends.
- The friend functions have access to private variables ints and len.
- In >> and <<, the type of the first argument and the return is &Stk.
Here is the header:
#include
#ifndef STK_H_
#define STK_H_
class Stk {
public:
int size();
int peek();
bool isempty();
friend Stk& operator >>(Stk& st, int i);
friend Stk& operator <<(Stk& st, int &i);
private:
int *ints = NULL;
int len = 0;
};
#endif /* STK_H_ */
Here is the main program:
#include
#include "Stk.h"
using namespace std;
int main() {
cout << "begin" << endl;
Stk st;
cout << "push 3: 13, 17, 19" << endl; st >> 13 >> 17 >> 19;
cout << "stack size=" << st.size() << endl;
cout << "pop the stack" << endl;
while (!st.isempty()) {
int n;
st << n;
cout << "popped n=" << n << endl;
}
cout << "stack size=" << st.size() << endl;
cout << "push 3: 29, 31, 37" << endl; st >> 29 >> 31 >> 37;
int i, j, k;
cout << "pop 2" << endl;
st << i << j;
cout << "i=" << i << " j=" << j << endl;
cout << "peek " << st.peek() << endl;
cout << "stack size=" << st.size() << endl;
cout << "push 2: 41, 47" << endl; st >> 41 >> 47;
cout << "pop 1" << endl;
st << k;
cout << "popped k=" << k << endl;
cout << "stack size=" << st.size() << endl;
// int p, q, r;
// st << p << q << r; // empty stack exception
cout << "done" << endl;
return 0;
}
Points to notice:
- Expression st >> 13 >> 17 >> 19 is evaluated left to right.
- st >> 13 is evaluated. The result is st, the stack with 13 pushed.
- Internally, the partially evaluated expression is now st >> 17 >> 19.
- st >> 17 is evaluated, and so on.
Output:
C:\Users\Brian Fitzgerald\eclipse-workspace\Stk\Debug>Stk.exe begin push 3: 13, 17, 19 stack size=3 pop the stack popped n=19 popped n=17 popped n=13 stack size=0 push 3: 29, 31, 37 pop 2 i=37 j=31 peek 29 stack size=1 push 2: 41, 47 pop 1 popped k=47 stack size=2 done
This is my Saturday project. The purpose was to refresh some skills and to use C++ language features in an interesting way. I saw something similar in one client’s Sybase CT-Library variable binding code. If we’re going to migrate the application to some other database connectivity library, we need to understand how the existing code works, and from there, develop a a migration action plan.
I am a database administrator, not a developer. Any comments or suggestions from anyone in any field are welcome.