A Stack.h állomány:
#ifndef STACK_H
#define STACK_H
#include<stdio.h>
#include<stdexcept>
#include<string>
class stack_exception: public std::exception
{
std::string message;
public:
stack_exception(std::string message):message(message){};
const char * what()const
{
return message.c_str();
}
};
class Stack
{
unsigned int elementNum;
int *pData;
public:
Stack() {elementNum=0;pData=NULL;}
// A másoló konstruktor szükséges a dinamikus adattagok miatt
Stack(const Stack& theOther);
// A destruktor felszabadítja a dinamikus adattagot
~Stack() {if(pData!=NULL) delete[]pData;}
bool isEmpty()const{return !elementNum;}
void pop(int& element);
void push(int element);
// Az = operátor, amely a mély másolást valósítja meg
const Stack& Stack::operator = (const Stack& theOther);
void readBinary(std::istream& is);
void writeBinary(std::ostream& os)const;
void readText(std::istream& is);
void writeText(std::ostream& os)const;
};
#endif /*STACK_H */
A Stack.cpp állomány:
#include <limits>
#include <assert.h>
#include "Stack.h"
#include <iostream>
#include <string>
using namespace std;
Stack::Stack(const Stack& theOther)
{
// Az operator=-t hívjuk,
// és az érvényes adatot feltételez
pData = NULL;
*this=theOther;
}
const Stack& Stack::operator = (const Stack& theOther)
{
assert(this != &theOther);
// Felszabadítjuk az eddigi adatokat
if(pData!=NULL)
{
delete [] pData;
}
// Átmásoljuk a másik verem tartalmát
if(theOther.elementNum==0)
{
elementNum=0;
pData=NULL;
}
else
{
elementNum=theOther.elementNum;
pData=new int[elementNum];
for(unsigned int i=0;i<elementNum;i++)
{
pData[i]=theOther.pData[i];
}
}
return *this;
}
void Stack::pop(int& element)
{
if(elementNum==0)
{
throw stack_exception("Data request from empty stack.");
return;
}
if(elementNum==1)
{
element=pData[0];
delete []pData;
pData=NULL;
elementNum=0;
return;
}
elementNum--;
element=pData[elementNum];
int* pTemp=new int[elementNum];
for(unsigned int i=0;i<elementNum;i++)
{
pTemp[i]=pData[i];
}
delete[] pData;
pData=pTemp;
}
void Stack::push(int element)
{
// C++-ban az UINT_MAX helyett a limits headerben található
// numeric_limits sablont használjuk a maximális unsigned int érték
// lekérdezésére
if(elementNum==numeric_limits<unsigned int>::max())
{
throw stack_exception("Stack is full.");
return;
}
int* pTemp=new int[elementNum+1];
for(unsigned int i=0; i<elementNum;i++)
{
pTemp[i]=pData[i];
}
pTemp[elementNum]=element;
if(pData)delete[]pData;
pData=pTemp;
elementNum++;
}
void Stack::readBinary(std::istream& is)
{
// Figyeljük meg a "mindent vagy semmit" megközelítést:
// csak akkor változtatjuk az objektum állapotát, ha minden sikerült.
// Csinálhatnánk egy ideiglenes veremmel, de az lassabb lenne, mert elemenként
// tudnánk csak beolvasni.
unsigned int elementNum;
is.read((char*) &elementNum, sizeof(elementNum));
if(!is)
return;
if(elementNum == 0)
{
// Töröljük az előzőt
delete pData;
pData = NULL;
return;
}
int* pTemp = new int [elementNum];
is.read((char*)pTemp, sizeof(pTemp[0])*elementNum);
// Csak akkor változtatjuk meg a verem állapotát, ha a beolvasás sikeres volt.
// Így tartjuk fenn a konzisztenciát.
if(is)
{
// Töröljük a dinamikus adatterületet
delete [] pData;
this->elementNum = elementNum;
pData = pTemp;
}
else
{
// Ha nem sikerült az elemek beolvasása, akkor töröljük az ideiglenes változót
delete[] pTemp;
}
}
void Stack::writeBinary(std::ostream& os)const
{
// Először kiírjuk, hány elem van, utána pedig az elemek következnek
os.write((const char*)&elementNum,sizeof(elementNum));
os.write((const char*)pData,sizeof(pData[0])*elementNum);
}
void Stack::readText(std::istream& is)
{
// Ideiglenes verem: ha hiba van, akkor nem módosítjuk az objektum állapotát
Stack s;
int elem;
while(is >> elem)
{
s.push(elem);
}
if(is.eof()) // Ha hiba van, de az eof
{
*this = s;
is.clear(ios::eofbit); // A hibát töröljük, az EOF állapotot nem
}
}
void Stack::writeText(std::ostream& os)const
{
for(unsigned int i=0; i<elementNum;i++)
{
os << ' ' << pData[i];
}
}
#include <iostream>
#include <fstream>
#include "Stack.h"
using namespace std;
void main(void)
{
Stack s1;
s1.push(1);
s1.push(2);
s1.push(3);
try
{
// Beolvasás tesztelése
// EOF: Windows: <Enter>Ctrl+Z<Enter>, Linux: Ctrl+D <Enter>
cout << "Stack element, separated with spaces, ending with EOF): ";
s1.readText(cin);
if(cin)
{
s1.writeText(cout);
cout << endl;
}
else
{
cerr << "Error reading stack." << endl;
}
// Tesztelés állományokkal
// (a destruktor lezárja az állományt, csak akkor zárjuk le a close tagfüggvénnyel,
// ha az állományt megakarjuk nyitni.)
// 1. Kiírás bináris állományba
ofstream outFileBinary("stack.bin", ios::out|ios::binary);
s1.writeBinary(outFileBinary);
outFileBinary.close();
// 2. Beolvasás bináris állományból
ifstream inFileBinary ("stack.bin", ios::in|ios::binary);
Stack s2;
s2.readBinary(inFileBinary);
if(inFileBinary)
{
s2.writeText(cout); cout << endl;
}
else
{
cerr << "Error reading stack." << endl;
}
// 3. Kiírás szöveges állományba
ofstream outFileText("stack.txt", ios::out);
s1.writeText(outFileText);
outFileText.close();
// 4. Beolvasás szöveges állományból
ifstream inFileText("stack.txt", ios::in);
s2.readText(inFileText);
if(inFileText)
{
s2.writeText(cout); cout << endl;
}
else
{
cerr << "Error reading stack." << endl;
}
}
catch(const stack_exception& e) // Elkapjuk a Stack kivételeit
{
cout << e.what() << endl;
}
}