Skip to the content.
#include <iostream>

class Image
{
public:
    Image(size_t size) : size(size), pixel_array(new Pixel [size]) {}
    ~Image() {delete [] pixel_array;}

    void print_Image()
    {
        for(size_t i = 0; i != size; ++i)
        {
            std::cout << "Pixel[" << i << "] = ";
            pixel_array[i].print_Pixel();
            std::cout << "\n";
        }
    }

private:
    class Pixel
    {
    public:
        Pixel(int r = 0, int g = 0, int b = 0) : r(r), g(g), b(b) {}
    
        void print_Pixel()
        {
            std::cout << "(" << r << "; " << g << "; " << b << ")";
        }
    
    private:
        int r;
        int g;
        int b;
    };

    size_t size;
    Pixel * pixel_array;
};

int main()
{
    Image i(5);
    i.print_Image();
    return 0;
}

Прикольная фишка

#include <iostream>
#include <cstring>

struct String 
{
    String(const char *str = "") : size(strlen(str)), str(new char[size])
    {  
        for(size_t i = 0; i != size; ++i)
            this->str[i] = str[i];
    }

    String(size_t n, char c) : size(n), str(new char[size])
    {
        for(size_t i = 0; i != size; ++i)
            str[i] = c;
    }

    ~String()
    {
        delete []str;
    }

    String(const String &other)
    {
        size = other.size;
        str = new char [other.size];
        for(size_t i = 0; i != size; ++i)
            str[i] = other.str[i];
    }

    String &operator=(const String &other)
    {
        size = other.size;
        str = new char [other.size];
        for(size_t i = 0; i != size; ++i)
            str[i] = other.str[i];
        return *this;
    }

    void append(const String &other)
    {
        size_t tmp_size = size + other.size;
        char * tmp = new char [tmp_size];
        for (size_t i = 0; i != tmp_size; ++i)
        {
            if (i < size)
            {
                tmp[i] = str[i];
            }
            else
            {
                tmp[i] = other.str[i-size];
            }
        }
        delete [] str;
        str = tmp;
        size = tmp_size;
    }

    struct String2
    {
        String2(const char * str = "", size_t start=0) : str(str), start(start) {}

        String operator[](size_t end) const
        {
            char * tmp = new char [end - start + 1];
            for(size_t i = start; i != end; ++i)
                tmp[i - start] = str[i];
            tmp[end - start] = '\0';
            String t(tmp);
            delete [] tmp;
            return t;
        }

        const char * str;
        size_t start;
    };

    String2 operator[](size_t i) const
    {
        return String2(str, i);
    }

    size_t size;
    char * str;
};

int main()
{
    String hello("hello");

    String const hell = hello[0][4]; // теперь в hell хранится подстрока "hell"
    String const ell  = hello[1][4]; // теперь в ell хранится подстрока "ell"

    return 0;
}

Первый оператор индексации ([]) вызывает перегрузку в String, которая создаёт и возвращает экземпляр класса String2, в поле которого записывается start, потом второй оператор индексации уже вызывает перегрузку для String2 и передаёт туда end, таким образом через 2 оператора индексации можно передать start и end например в данном случае что бы вернуть подстроку.