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:
- STL Iteratorlerine Bir Temel Sınıf Vermek
- C++ Iteratorleri için Tip Silme
- any_iterator Sınıf Referansı
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.