Skip to content

Instantly share code, notes, and snippets.

@vishal-keshav
Last active January 26, 2019 15:42
Show Gist options
  • Save vishal-keshav/a504b74c175dfd741c870f9497a94918 to your computer and use it in GitHub Desktop.
Save vishal-keshav/a504b74c175dfd741c870f9497a94918 to your computer and use it in GitHub Desktop.
On Object oriented programming and design patterns in C++ part 10

Design Principles Part 10

Iterators abstract the complex structures and gives a clean interface to access the data. C++ already provides containers like vector, maps, queues, etc. which implements iterator patterns.

In order to implement a C++ style iterators on a container (class), iterators in the class namespace has to be defined with increment and access functionality overloaded. Below code demostrate this.

Iterator desing pattern

#include "stdafx.h"
#include <iostream>
#include <vector> // vector<> - array
#include <list> // list<> - doubly linked list
#include <forward_list> // forward_list<> - singly list list

using namespace std;

class myvector
{
private:
	// Internal representation is a list
	int item[3];
public:
	myvector(){
		item[0] = 100;
		item[1] = 200;
		item[2] = 300;
	}
	
	class iterator
	{
	private:
		int _index;
		myvector *mv;
	public:
		iterator(int index, myvector* mv) :_index(index), mv(mv){

		}
		iterator(int index) :_index(index){

		}
		bool operator != (/* iterator *this = &bit */const iterator& eit){
			return this->_index != eit._index;
		}

		int operator* (/* iterator *this = &bit */){
			return this->mv.item[_index];// Not mv->item[_index]
		}
		void operator++() // pre-increment operator overloading
		{
			_index++;
		}
		void operator++(int dummy) // post-increment operator overloading
		{
			_index++;
		}

	};

	iterator begin(/* myvector *this */){
		return iterator(0);
	}

	iterator end(/* myvector *this */){
		return iterator(3);
	}
};

class mylist
{
private:
	class Node // Nested class, not accesible outside(in private)
	{
	public:
		int data;
		Node *next = nullptr; // Inplace initialization

	};
	Node *head; //Internal representation is such that no random access
public:
	mylist(){
		head = new Node();
		head->data = 100;
		head->next = new Node();
		head->next->data = 200;
		head->next->next = new Node();
		head->next->next->data = 300;

	}

	class iterator
	{
	private:
		Node* _ptr;
	public:
		iterator(Node *ptr) :_ptr(ptr){
		}

		bool operator != (/* iterator *this = &bit */const iterator& eit){
			return this->_ptr != eit._ptr;
		}
		int operator* (/* iterator *this = &bit */){
			return this->_ptr->data;
		}
		void operator++ (){
			this->_ptr = this->_ptr->next;
		}
		void operator++ (int dummy){
			this->_ptr = this->_ptr->next;
		}

	};

	iterator begin(/* mylist *this */){
		return iterator(head);
	}

	iterator end(/* mylist *this */){
		return iterator(nullptr);
	}
};

int main()
{

	myvector mv;
	mylist ml;

	for (int d : mv){
		cout << d << " ";
	}

	for (int d : ml){
		cout << d << " ";
	}

	// range-for
	vector<int> numbers = {1,2,3,4,5};
	for (int number : numbers){
		cout << number << " ";
	}
	// Internals of range-for
	for (vector<int>::iterator bit = numbers.begin(); bit != numbers.end(); bit++){
		int number = *bit;
		cout << number << " ";
	}
	int stop;
	cin >> stop;
	return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment