C++ and OOP

Started by
6 comments, last by Amnesty2 17 years ago
Hi guys! I recently started learning OOP at a higher level than I already knew it(that is near 0). I came across this class and I there a few things I don't understand about it(sadly, I don't have the implementation)

class Vector
{
	private:
	    int   *data_;	
	    size_t size_;	
	public:
	    class Iterator;					
		friend class Iterator;	  
	
		Vector(): data_(0), size_(0){};	
		Vector(int e, size_t psize );	
		Vector(const Vector&);	
		Vector(const int *pbegin, const int *pend );
			
		void resize(int n );	
		int size()const;	
		const int& operator[](int)const;
		int& operator[](int);	
	
		const Iterator begin() const;
		Iterator begin();	
		const Iterator end();
		Iterator end();		
	
		class Iterator
		{
		    private:
				Vector *data_;
				int *elem_;
		    public:
				Iterator(): data_(0), elem_(0){};
				Iterator(Vector);
				const int& operator*()const;
				int& operator*();
				Iterator& operator++();		
				const Iterator operator++(int);	
		};
};



All I understand is that this class would implement a STL like vector. But what does the private variable Iterator::Vector *data_ could be used for? and how would one implement these functions: const Iterator end(); Iterator end(); The rest of the code seems pretty clear to me. [Edited by - gpulove on March 25, 2007 3:33:31 AM]
Advertisement
Moved to For Beginners.
probably a pointer to the array of the iterated vector, not sure though
For a vector an iterator can simply be a pointer to the internal array. An end iterator can simply be a pointer to 1 beyond the end of the current size of the vector. (start_ptr[size])

My guess the purpose of the "Vector *data_" in that code is to help make sure that the iterator is used only in conjunction with other iterators to the same vector.

EDIT: Speaking of which, your vector lacks a separate capacity member. A vector should not have to allocate new memory every time it changes size. Instead it should contain a large array, only part of which is used for storing it's contents. You should only reallocate the array when it gets full -- then you double it's size.

Thus it should have a separate size and capacity. The size is the vectors is the amount of objects (integers) it contains. The capacity is the size of the allocated array and is always >= the size.
Quote:Original post by gpulove
But what does the private variable Iterator::Vector *data_ could be used for?


First off, be sure you understand that Vector objects don't contain any Iterator object :) Rather, the Iterator *class* is defined inside the Vector class, to restrict its scope.

The idea is that when the Vector creates a Vector::Iterator object (e.g. to implement begin() or end()), the created Iterator will store a pointer back to the Vector that created it. That way, the Iterator knows what it's iterating over. (This is a "weak" pointer; it implies no ownership of memory, so the Iterator destructor will *not* delete the pointer.) Of course, because there is already a separate pointer to some 'data' position, it's redundant :) The interface of the standard library containers doesn't require that an iterator provide a way to find the container - just its elements. However, it could be useful for debugging.

Quote:
const Iterator end();
Iterator end();


An 'end' iterator is supposed to point one past the end of a collection - the iterator can be compared to, but cannot be dereferenced. The idea is that the distance from the 'begin' to the 'end' is equal to the size of the container.

Since our Vector holds all its elements in a dynamically allocated array, all the elements are right next to each other in memory, so we simply need a pointer to an element that is size-many elements after the beginning. We simply do a little pointer arithmetic. (The Iterator interface shown actually is not really adequate for the job :) )

Vector::Iterator Vector::end() {  return Iterator(this, data + size);}// Get rid of the other Iterator constructors, and provide this one instead:Vector::Iterator(Vector* owner, int* pos) : data_(owner), elem_(pos) {}


BTW, the const overloads that are shown also aren't correct. That is, they'll work, but they're too restrictive. :) A 'const Iterator' is one that can't change what element it refers to... usually not very useful. Instead, we need to define a separate class 'ConstIterator' (or as the standard library spells it, const_iterator), which is an iterator that can't change *the* element it refers to. ;) (I.e., we want to be able to point it at different elements, but the elements themselves should be const). The idea is that if the container is const, then its elements should be const (because those are logically part of the container, even if they're hidden behind a pointer) but the iterator doesn't need to be (because it's a separate object).
Well you can start by deleting the interior iterator class.
And redefine it like so

typedef int* iterator;typedef const int* const_iterator;typedef std::reverse_iterator<iterator> reverse_iterator;typedef std::reverse_iterator<const_iterator> const_reverse_iterator;


It doesnt need to be an class. It was only made as class in that source you found because for some reason the programer wanted a pointer back to the container (Vector* _data) to do some things.

Thanks guys, you cleared up a lot of things for me. But I have one more question:
How can I store a pointer to the current Vector object I'm iterating through IF the only constructor of the iterator class is
Iterator(Vector)
which doesn't take as an argument a pointer to a Vector object but a Vector object. I can't get the pointer like so:
Iterator(Vector v)
{
_data = &v
}

Because v is on the stack and after Iterator::Iterator(Vector v) finishes v will be no longer valid(well it will still remain on the stack, there's no data overriden to delete him, BUT IT could be overriden by other instructions that use that stack area, moreover after Iterator::Iterator finishes, the destructor for object v will be called).

What's with this constructor? is it wrong, or... maybe I'm just missing something :)
You would need to change that definition to
iterator(Vector& v) : _data(&v) {}

But i find iterators that store the container pretty icky. You shouldnt bother implementing one unless you have a really good reason for doing so.

Just change those iterators to the typedefs I already mentioned.


BTW - Its a pretty shady code to investigate to learn more about OOP.

This topic is closed to new replies.

Advertisement