C++‘da Çeşitli Kaplardan Erişimin Genel Yolunu Bulmak

Modern C++‘da geliştiricilerin karşılaştığı yaygın bir zorluk, farklı kap türleri üzerinde tek tip döngü oluşturmaktır. Birkaç kapsayıcınız var: standart std::vector, std::list ve özel bir liste. Her kapsayıcının kendine özgü bir iterator türü vardır, bu da temiz ve sürdürülebilir kod yazmayı zorlaştırabilir. Bu blog yazısında, bu sorunu inceleyecek ve bu kaplara genel erişim sağlamak için şık bir çözüm sunacağız.

Sorun

Bu çeşitli kaplar üzerinde öğelere erişmeye çalıştığınızda, hızla bir sorunla karşılaşırsınız. Foo sınıfınızda, std::vector<int>, std::list<int> ve özel listenizle etkileşimde bulunacak tek bir iterator istiyorsunuz. Ancak, bu tüm kaplar farklı iterator türleri döndürdüğü için, bir iterator atama girişimleriniz tür çatışmalarına yol açar.

Karşılaştığınız zorluğun basitleştirilmiş bir versiyonu:

class Foo {
public:
    Foo() {
        std::list<int> x;
        std::vector<int> y;
        custom_list<int> z;

        iter = x.begin(); // Veya
        iter = y.begin(); // Veya
        iter = z.begin(); // Sorun: Farklı iterator türleri
    };
private:
    std::iterator<int> iter; // Bu çalışmaz
};

Çözüm

Bu sorunu çözmek ve kodunuzu şık ve yönetilebilir tutmak için tip silme (type erasure) olarak bilinen bir kavramı kullanabiliriz. Bu teknik, farklı kapsayıcı türleri boyunca öğelere erişimin tek tip bir yolunu sağlayarak genel bir iterator arayüzü oluşturmanıza olanak tanır.

Adım 1: Temel Iterator Sınıfı

Tüm iteratorlerin miras alacağı bir temel arayüz tanımlayarak başlayacağız. Bu, farklı iterator türleri ile etkileşimde bulunmak için ortak bir yaklaşım sağlar.

class IIterator {
public:
    virtual ~IIterator() = default;
    virtual int& operator*() = 0; // Dereference operatörü
    virtual IIterator& operator++() = 0; // Artırma operatörü
    virtual bool operator!=(const IIterator& other) const = 0; // Karşılaştırma operatörü
};

Adım 2: Her Kap Türü için Uygulama

Sonraki adım, bu arayüzü farklı kap türleri için uygulamak olacak.

std::vector için

class VectorIterator : public IIterator {
    std::vector<int>::iterator it;
public:
    VectorIterator(std::vector<int>::iterator iterator) : it(iterator) {}
    int& operator*() override { return *it; }
    IIterator& operator++() override { ++it; return *this; }
    bool operator!=(const IIterator& other) const override {
        return this->it != dynamic_cast<const VectorIterator&>(other).it;
    }
};

std::list için

class ListIterator : public IIterator {
    std::list<int>::iterator it;
public:
    ListIterator(std::list<int>::iterator iterator) : it(iterator) {}
    int& operator*() override { return *it; }
    IIterator& operator++() override { ++it; return *this; }
    bool operator!=(const IIterator& other) const override {
        return this->it != dynamic_cast<const ListIterator&>(other).it;
    }
};

Özel Liste için

Özel listenizin bir iterator tanımladığını varsayarak, benzer bir şekilde uygulayacaksınız:

class CustomListIterator : public IIterator {
    custom_list<int>::iterator it;
public:
    CustomListIterator(custom_list<int>::iterator iterator) : it(iterator) {}
    int& operator*() override { return *it; }
    IIterator& operator++() override { ++it; return *this; }
    bool operator!=(const IIterator& other) const override {
        return this->it != dynamic_cast<const CustomListIterator&>(other).it;
    }
};

Adım 3: Foo’da Iteratorlerin Kullanımı

Artık, Foo sınıfınızda, herhangi bir kap türünü işlemek için temel IIterator sınıfına tek bir türde işaretçi tutabilirsiniz.

class Foo {
public:
    Foo() {
        std::list<int> x;
        std::vector<int> y;
        custom_list<int> z;

        IIterator* iter;

        // Her bir kapsayıcının örneklerinin olduğunu varsayalım
        iter = new VectorIterator(y.begin());
        // Veya
        iter = new ListIterator(x.begin());
        // Veya
        iter = new CustomListIterator(z.begin());

        // Artık iter'i tek tip bir iterator olarak kullanabilirsiniz
    };
};

Sonuç

Tip silme kullanarak ortak bir iterator arayüzü aracılığıyla, C++‘da farklı kapsayıcı türlerini işlemek için şık bir yol sağladık. Bu, daha temiz ve sürdürülebilir bir kod yazarken birden fazla iterator türü yönetmenin baş ağrısını önlemeyi sağlar.

Bu konuya daha fazla keşif yapmak için bazı ilginç makaleleri inceleyebilirsiniz:

Bu çözüm sadece C++ becerilerinizi geliştirmekle kalmaz, aynı zamanda çeşitli kapsayıcı türlerini sorunsuz bir şekilde işleyebilen çok yönlü ve yeniden kullanılabilir kod yapıları oluşturmanıza yardımcı olur.