Reputation: 12237
Implementing iterators in real C++ application seems to be quite confusing to say the least. I am implementing this in a demo to understand iterators.
I have AudoDealer class, which has address etc and than it has the an actual list (in my case stl::list) that contains all the cars with that dealer. Now I want an iterator which can iterate through all the cars in that dealership.
First question is that should the concrete-iterator take in the AutoDealer
class or the actual list
inside this class which stores the cars? I would like it to take in AutoDealer class because that way it sort of have the ownership of the class and deals with it all together as oppose to an independent iterator which is posing only to an internal part of the structure but later seems better?
The 2nd question is that because I am using STL list class as my container, storing int currentItem
does't make sense but I should be rather storing std::list<>iterator
to traverse. Now I can't really get this iterator type to store to begin with! It will break the principle of exposing list implementation.
My code is below, it is still work in progress but everything is below and btw I am following gang of four book.
// IteratorDemo.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <list>
using namespace std;
template <class Object>
class Iterator
{
public:
virtual Object * first();
virtual Object * next();
virtual bool IsDone() const = 0;
virtual Object * currentItem() const = 0;
};
class Car
{
string make;
string model;
string price;
bool isTruck; // if true is truck, otherwise sedan (assume for this example)
};
//template <class Item>
class AutoDealer
{
public:
AutoDealer();
virtual ~AutoDealer();
// create iterator
//virtual Iterator<item> * CreateIterator() = 0;
virtual string GetDealerAddress()
{
return address;
};
virtual void SetDealerAddress(string addr)
{
address = addr;
}
virtual void SetNumberOfSedans() = 0;
virtual void SetNumberOfTrucks() = 0;
virtual Car * GetCar() = 0;
virtual void AddCar(Car car) = 0;
protected:
string address;
};
//template <class item>
class AutoDealerImpl : public AutoDealer
{
public:
AutoDealerImpl()
{
}
virtual ~AutoDealerImpl();
/* virtual Iterator<item> * CreateIterator()
{
return std::list<Car>::iterator;
}
*/
virtual void SetNumberOfSedans();
virtual void SetNumberOfTrucks();
virtual Car * GetCar();
virtual void AddCar(Car car)
{
carList.push_back( car );
}
protected:
std::list<Car> carList; // list implementation
};
template <class Object>
class AutoDealerIterator : public Iterator<Object>
{
public:
AutoDealerIterator( AutoDealer * theDealer )
{
// dealer = theDealer;
}
virtual Object * first()
{
}
virtual Object * next();
virtual bool IsDone() const = 0;
virtual Object * currentItem() const = 0;
protected:
AutoDealer * dealer;
int _currentItem; // this is an issue, it should be std::list<car>::iterator type here but how can I access that?
// I am not traversing a simple list but an STL list which already
// has its own iterator and I need that iterator to travese but how do I access it?
};
int _tmain(int argc, _TCHAR* argv[])
{
}
Update
I have another goal from this demo project which can bypass the previous questions.
As I have CAutoDealer
which is simply the interface and than AutoDealerImpl
which is concrete. The data members actually reside inside the concrete for encapsulation. How can I iterate through the data using the interface class?
My main objective is to iterate through std::list<Car>
in my application. Should the AutoDealer
have this responsibility or iterating this outside the main class is in line with OOP? My goal is a good Object Oriented Design and open to design patterns.
Upvotes: 0
Views: 333
Reputation: 153955
If you insist in having run-time polymorphic iterators you'd have your concrete iterator take a pair of std::list<Car>::iterator
s in a private
constructor and you'd make your AutoDealerImpl
a friend of your AutoDealerIterator
so it can construct them:
class AutoDealerIterator
: public Iterator<Car>
{
friend class AutoDealer;
std::list<Car>::iterator d_begin;
std::list<Car>::iterator d_it;
std::list<Car>::iterator d_end;
AutoDealerIterator(std::list<Car>::iterator begin, std::list<Car>::end)
: d_begin(begin)
, d_it(begin)
, d_end(end)
{
}
public:
Car * first() final { this->d_it = this->d_begin; return this->next(); }
Car * next() final { return ++this->d_it == this->d_end? 0: &*this->d_it; }
bool IsDone() const final { return this->d_it == this->d_end; }
Object * currentItem() const final { return &*this->d_it; }
};
Creating the actual AutoDealerIterator
object from an AutoDealer
should be trivial.
Note that using a run-time polymorphic iterator is generally a bad idea: it doesn't quite work and is also quite likely to be relatively slow. Furthermore it seems that most processing of sequences actually has a concrete idea of the objects it is processing.
Upvotes: 1