Nested Classes

(an example)

We will define Iterators as nested classes to our List classes. This will allow us to have customized Iterators for each of our List classes. For example, a simple list will need the Iterator to be able to give access to the _items in the list but restrict access to memory management. i.e. does not allow the caller to delete a node unless it goes through the List's Delete function. A Stack and a Queue would want access to see what is in the structure (to print or debug) but not change the items.

Here is a simple List class with a dynamic array and a nested Iterator:

template <class T>
class List{
public:
    class Iterator{
    //the nested class
    public:
        friend class List;                  //this will allow List
                                            //  to access the private
                                            //  members of Iterator
        Iterator next()                     //return an iterator to the 
        {                                   //  next location in the list
            return Iterator(p + 1);
        }

        Iterator(T* p = NULL):_ptr(p){}     //ctor
        T& operator *(){                    //dereference oprator
            assert(_ptr);
            return *_ptr;
        }

        friend Iterator operator ++(Iterator& it,       //it++
                                    int unused){
            Iterator hold;
            hold = it;
            it._ptr++;
            return hold;
        }
        Iterator& operator ++(){                        //++it
            _ptr++;
            return *this;
        }

        friend bool operator !=(const Iterator& left,   //it != it
                                const Iterator& right){
            return left._ptr != right._ptr;
        }

    private:
        T* _ptr;                    //pointer being
                                    //  encapsulated
    };

    List(T* array, int size);       //List ctor
    //---------------------------- big three -----------------------------------
    ~List();
    List(const List& other);
    List& operator =(const List& RHS);
    //---------------------------------------------------------------------------
    Iterator Begin() const;         //an iterator to the start of List
    Iterator End() const;           //an iterator to the end of List
private:
    T* _a_list;                     //the List raw data
    int _how_many;                  //size of List
};

Notes:

 

Class Function Definitions:

template <class T>
List<T>::List(T *array, int size){
    _a_list = copy_array(array, size);
    _how_many = size;

}
//---- BIG THREE --------------------------------
template <class T>
List<T>::~List(){
    destroy_array(_a_list);
}

template <class T>
List<T>::List(const List& other){
    _a_list = copy_array(other._a_list, other._how_many);
    _how_many = other._how_many;

}

template <class T>
List<T>& List<T>::operator =(const List& RHS){
    if (this == &RHS) return *this;
    destroy_array(_a_list);
    _a_list = copy_array(RHS._a_list, RHS._how_many);
    _how_many = RHS._how_many;
}
//-----------------------------------------------------


template <class T>
typename List<T>::Iterator List<T>::Begin() const{
    //C++ requires you to use the keyword typename when referring to the Iterator outside
    //      the class declaration
    return Iterator(_a_list);
}

template <class T>
typename List<T>::Iterator List<T>::End() const{
    //probably a terrible idea!
    return Iterator(_a_list+_how_many);
}



template <class T>
void destroy_array(T* &src){
    if (src){
        delete[] src;
    }
    src = NULL;
}

template <class T>
T* copy_array(T* src, int size){
    T* copy = new T[size];
    for (int i=0; i<size; i++){
        copy[i] = src[i];
    }
    return copy;
}

The calling function:

int main(int argc, char *argv[])
{
    cout <<endl<<endl<< "=======================" << endl<<endl;
    cout<<endl<<endl<<"Testing a list of ints:"<<endl;
    int a[] = {1,1,3,5,8,13};           //an array! (sorry about this!)
    List<int> list(a, 6);               //instantiate a List object
    List<int>::Iterator it;             //a List Itertor object
    for (it=list.Begin(); 
         it!=list.End(); 
         it++){                         //postfix ++
        //looping through all the elements of List using the Iterator
        cout<<*it<<"|";
    }
    //delete it;      //cannot be done.
    //delete it._ptr; //cannot be done.
    cout<<endl<<endl<<"Testing a list of strings:"<<endl;
    //
    string s[] = {string("Curly"), string("Moe"), string("Larry")};
    List<string> slist(s, 3);
    List<string>::Iterator sit;           //a List Itertor object
    for (sit=slist.Begin(); 
         sit!=slist.End(); 
         ++sit){                          //prefix ++
        //looping through all the elements of List using the Iterator
        cout<<*sit<<"|";
    }

    cout<<endl;
    cout <<endl<<endl<< "=======================" << endl<<endl;
    return 0;
}

The output:

=======================



Testing a list of ints:
1|1|3|5|8|13|

Testing a list of strings:
Curly|Moe|Larry|


=======================