Home C++ Introduction Decisions Loops Input/Output Functions Stack and Heap References Arrays Searching and Sorting Recursion Pointers Character and Strings Structures Classes Inheritance Exceptions Templatess STL Modern C++ Misc Books ----

Contents

Iterator

We have been using the "iterator" class to traverse the container. In this section we take a closer look as to how they are implemented and study them in a bit more detail.

Inner Classes

A class can exist in another class. That class is called the inner class. An inner class is a separate class from the outer class and does not have automatic access to the outer class. It's data members are separate from the outer class. However it cam access the private data members if given an outer class object. We can think of the inner class as a normal class but in the scope of the outer class. They are not connected in any other way.

File: inner1.cpp
#include <iostream>
#include <vector>


using namespace std;



class EnclosingClass
{
    private:
        int private_data ;

    public:
        EnclosingClass( int  private_dataP )
         {
           private_data = private_dataP  ;
         }

        class NestedClass
        { // Nested class definition
                public:
                    void innerMethod()
                     {
                       cout << "Inside innerMethod" << endl ;
                     }
                    void innerMethodToChangeData(EnclosingClass* obj)
                    {
                        // NestedClass can access private members of EnclosingClass
                        // through an instance of EnclosingClass
                        obj->private_data = 10;
                        cout << "Inside innerMethodToChangeData." <<
                        endl ;
                    }
        };

    void outermethod()
    {
        cout << "Inside outer class method: " << private_data << endl ;
    }

};

int main()
{
    //Create an object of inner class
    EnclosingClass::NestedClass nested_obj ;
    nested_obj.innerMethod()  ;

    EnclosingClass  enclosingClassObject1( 5 )  ;
    nested_obj.innerMethodToChangeData( &enclosingClassObject1 ) ;
    enclosingClassObject1.outermethod()  ;


    return 0;
}
$ g++ inner1.cpp ; ./a.exe
Inside innerMethod
Inside innerMethodToChangeData.
Inside outer class method: 10
The below is a custom implementation of how the actual class "vector" might implement it's iterators.

File: inner2.cpp
#include <iostream>
#include <iterator> // For iterator_traits, random_access_iterator_tag
#include <algorithm>

using namespace std ;

template <typename T>
class MyVector {
private:
    T* data_;
    size_t size_;
    size_t capacity_;

public:
    // MyVector constructor, destructor, push_back, etc. (simplified for brevity)
    MyVector() : data_(nullptr), size_(0), capacity_(0) {}
    ~MyVector() { delete[] data_; }

    void push_back(const T& value) {
        if (size_ == capacity_) {
            // Reallocate and copy data
            size_t new_capacity = (capacity_ == 0) ? 1 : capacity_ * 2;
            T* new_data = new T[new_capacity];
            for (size_t i = 0; i < size_; ++i) {
                new_data[i] = data_[i];
            }
            delete[] data_;
            data_ = new_data;
            capacity_ = new_capacity;
        }
        data_[size_++] = value;
    }

    T& operator[](size_t index) { return data_[index]; }
    const T& operator[](size_t index) const { return data_[index]; }
    size_t size() const { return size_; }

    // Custom iterator nested class
    class Iterator {
    public:
        using iterator_category = random_access_iterator_tag;
        using value_type = T;
        using difference_type = ptrdiff_t;
        using pointer = T*;
        using reference = T&;

        Iterator(T* ptr) : ptr_(ptr) {}

        // Dereference operators
        reference operator*() const { return *ptr_; }
        pointer operator->() const { return ptr_; }

        // Increment operators
        Iterator& operator++() { // Pre-increment
            ++ptr_;
            return *this;
        }
        Iterator operator++(int) { // Post-increment
            Iterator temp = *this;
            ++ptr_;
            return temp;
        }

        // Decrement operators
        Iterator& operator--() { // Pre-decrement
            --ptr_;
            return *this;
        }
        Iterator operator--(int) { // Post-decrement
            Iterator temp = *this;
            --ptr_;
            return temp;
        }

        // Arithmetic operators
        Iterator operator+(difference_type n) const { return Iterator(ptr_ + n); }
        Iterator operator-(difference_type n) const { return Iterator(ptr_ - n); }
        difference_type operator-(const Iterator& other) const { return ptr_ - other.ptr_; }

        Iterator& operator+=(difference_type n) { ptr_ += n; return *this; }
        Iterator& operator-=(difference_type n) { ptr_ -= n; return *this; }

        // Comparison operators
        bool operator==(const Iterator& other) const { return ptr_ == other.ptr_; }
        bool operator!=(const Iterator& other) const { return ptr_ != other.ptr_; }
        bool operator<(const Iterator& other) const { return ptr_ < other.ptr_; }
        bool operator>(const Iterator& other) const { return ptr_ > other.ptr_; }
        bool operator<=(const Iterator& other) const { return ptr_ <= other.ptr_; }
        bool operator>=(const Iterator& other) const { return ptr_ >= other.ptr_; }

    private:
        T* ptr_;
    };

    // begin() and end() methods returning the custom iterator
    Iterator begin() { return Iterator(data_); }
    Iterator end() { return Iterator(data_ + size_); }
    const Iterator cbegin() const { return Iterator(data_); }
    const Iterator cend() const { return Iterator(data_ + size_); }
};

int main()
{
    MyVector<int> vec;
    vec.push_back(10);
    vec.push_back(30);
    vec.push_back(20);

    // Using the custom iterator with a range-based for loop
    //MyVector needs to implement begin() and end() methods
    for (int x1 : vec) {
        cout << x1 << " ";
    }
    cout << endl;

    // Using the custom iterator with explicit begin/end
    for (MyVector<int>::Iterator it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    sort( vec.begin() ,   vec.end()  )  ;

    for (MyVector<int>::Iterator it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

$ g++ inner2.cpp ; ./a.exe
10 30 20
10 30 20
10 20 30

How did "sort" work even though it did not about our custom class. It worked
because "sort" is a template function and the iterator class was passed as a
template paramter implicitly. All the sort function needs to do is
use "*" and "++" , "--" operators to move and access the values.