Hi guys,

Design question:

I have a class that contains 2 vectors, and I'd like for that class to provide a public interface to access the next element in either list. The easy way to do it is to obviously return the list itself, either const or not, but this seems to go completely against data abstraction. If I have a function like: const std::vector<std::string>& GetCommandList() const then I'm telling anyone that uses my class that they can expect a string vector, and now I'm stuck with vector, even if I want to change the storage solution in the future.

As c++ doesn't seem to have a generic iterator, what do people usually do for this? Do I create a custom iterator class for each list? This really seems excessive...

If i'm not mistaken, you should be able to return the vector iterator.
Maybe an example will help.

#include <iostream>
#include <vector>
#include <string>
#include "print.h"

using namespace std;

class Items{
public:	
	typedef std::vector<string> ItemType;
	typedef std::vector<string>::iterator Iterator;
	typedef std::vector<string>::const_iterator constIterator;
private:
	ItemType _weapons;
	ItemType _potions;
public:	
	Items(){
		_weapons.push_back("sword"); 
		_weapons.push_back("knife");
		_weapons.push_back("club");
		_weapons.push_back("Ak47");
		
		_potions.push_back("20Plus");
		_potions.push_back("40Plus");
		_potions.push_back("100Plus");
		_potions.push_back("HealAll");
		_potions.push_back("Revive");
	}

	Iterator WeaponStartIterator(){ return _weapons.begin(); }
	Iterator WeaponEndIterator(){ return _weapons.end(); }
	constIterator WeaponStartIterator()const{ return _weapons.begin();}
	constIterator WeaponEndIterator()const{ return _weapons.end();}

	constIterator PotionStartIterator()const{ return _potions.begin(); }
	constIterator PotionEndIterator()const { return _potions.end(); }
	Iterator PotionStartIterator(){ return _potions.begin(); }
	Iterator PotionEndIterator() { return _potions.end(); }

};
void printItems(Items::constIterator start, Items::constIterator end){
	while(start != end){	cout << *start++  << " ";	}
}
int main(){
	Items itm;
	cout << "WeaponList { ";
	printItems(itm.WeaponStartIterator(),itm.WeaponEndIterator());
	cout << "}"<< endl;
	
	cout << "PotionLIst { ";
	printItems(itm.PotionStartIterator(),itm.PotionEndIterator());
	cout << "}" << endl;
}

Absolutely, you can do that. But you're still tying yourself to using a vector, because you're returning a vector<string>::iterator object. Imagine if down the road I need to use a queue instead -- now what? I'm thinking of doing that, but it still feel like I'm violating encapsulation here.

Absolutely, you can do that. But you're still tying yourself to using a vector, because you're returning a vector<string>::iterator object. Imagine if down the road I need to use a queue instead -- now what? I'm thinking of doing that, but it still feel like I'm violating encapsulation here.

well do you think you will need queue "down the road" ?

Why do you think its violating encapsulation?


And btw, queue does not have iterators.

Ah, I made a poor choice with queue then. Let's take a better example and say set -- one of my vectors is currently for a sequence of commands, and perhaps down the road I decide that there can be no duplicates in that sequence. Now, set<string>::iterator is a lot more appropriate than vector<string>::iterator, but my clients are already tied to using the vector version. When what I'm trying to represent is simply a way to get the next object in a collection, and yet I'm tied to one implementation, isn't that the reason you don't violate abstraction? IMO, my users shouldn't care what kind of collection I use, so long as they can view all elements in that collection.

This article has been dead for over six months. Start a new discussion instead.