c++ - Implementing Data Structure using levels of abstraction -
lets assume i'm implement stack using dynamic array allocation. have following classes , functions.
data.h
class data { public: data(std::string fname, int age) : name(fname) , age(age) {} private: std::string name; int age; }
stackarray.h
#include "data.h" class stackarray { public: stackarray(int ssize) : size(ssize), top(-1) { dataarray = new data[size]; }; ~stackarray() { delete[] dataarray; }; stackarray& operator=(stackarray& stackarrayobj) { //use copy&swap here }; stack(const stackarray& stackarrayobj); bool isfull(); bool isempty(); void push(data& dataobj); void pop(); private: data* dataarray; int top; int size; }
if implement above, works quite well. of recent, i've been asked implement above 2 is, have separate implementation core stack functionalities.
so now, if move push
, pop
, isfull
, isempty
new stack definition, purpose of class stackarray
implemtation?.
the 2 solution have tried follows:
new class implemtation
class stackadt { public: stackadt(); virtual ~stackadt() = 0; virtual bool isfull() = 0; virtual bool isempty() = 0; virtual void push(data& dataobj) = 0; virtual void pop() = 0; }
then, extending class stackarray
class, thereby forcing implement pure virtual function.
the second, not elegant(my opinion) way have done that:
i have complete definition , implementation of stack in stackadt
, , calling corresponding methods in equivalent methods in stackarray
. this:
stackadt - push
bool stackadt::push(const data& dataobj) { if(!isfull) return false; else { top++; dataarray[top] = dataobj; } return true; }
then inside stackarray - push
, i'll this:
bool stackarray::push(const data& dataobj) { stackadt dopush; dopush.push(dataobj); }
not sure both methods of combining 3 classes - data, container , stack - suppose be.
how can solve design problem? or @ least align "best practice" if there's such.
when talking abstractions, should try identify core aspects of trying implement. normally, aspects can represented interface.
since in c++, unlike other languages java, not have specific interface declaration syntax, can use pure virtual classes.
generically speaking, stack data structure following lifo access structure , nothing more.
even though being limited amount of memory, don't see reason why basic stack should have size limit @ first. more abstracted way of thinking size limit verify whether stack accepts more elements or can provide , element through pop
invocation.
so, might think stack basic interface follows:
class stack { public: virtual ~stack()=0; virtual data& pop() throw (std::out_of_range) = 0; virtual void push(data&) throw (std::out_of_range) = 0; virtual bool ispoppable() = 0; virtual bool ispushable() = 0; }
then can start thinking implementations. simple implementation doing array:
class stackarray : public stack { private: data* marray; int msize; int mpointer; stackarray(int size) : msize(size), mpointer(0) { marray = new data[msize]; } virtual ~stackarray() { delete [] marray; } public: void push(data& el) throw (std::out_of_range) { if (!ispushable()) throw std::out_of_range("cannot push stack"); marray[mpointer++] = el; } data& pop() throw (std::out_of_range) { if (!ispopable()) throw std::out_of_range("cannot pop stack"); return marray[mpointer--]; } bool ispushable() { return mpointer < msize; } bool ispoppable() { return mpointer > 0; } }
going further, think of linked-list-based stack:
class datanode { private: datanode* next; data* data; public: // trivial impl. ommited bool hasnext(); datanode* getnext(); data* getdata(); void setnext(datanode* next); void setdata(data* data); } class stacklinkedlist : public stack { private: datanode* root; public: stacklinkedlist():pointer(0) {} virtual ~stacklinkedlist() {} void push(data& el) throw (std::out_of_range) { if (!ispushable()) throw std::out_of_range("cannot push stack"); datanode* n = new datanode(); n->setdata(&el); datanode* pointer = root; if (root == null) { pointer = n; } else { while (pointer->hasnext()) { pointer = pointer->getnext(); } pointer->setnext(n); } } data& pop() throw (std::out_of_range) { if (!ispoppable()) throw std::out_of_range("cannot pop stack"); datanode* pointer = root, previous = null; while (pointer->hasnext()) { previous = pointer; pointer = pointer->getnext(); } data* ret = pointer->getdata(); delete pointer; if (previous != null) { previous->setnext(null); } return *ret; } bool ispushable() { return true; } bool ispoppable() { return root != null; } }
Comments
Post a Comment