Mencari Cara Generik untuk Mengakses Kontainer Beragam di C++
Dalam C++ modern, satu tantangan umum yang dihadapi pengembang adalah mengiterasi berbagai jenis kontainer secara seragam. Bayangkan Anda memiliki beberapa kontainer: std::vector
standar, std::list
, dan sebuah daftar kustom. Setiap kontainer memiliki jenis iterator yang unik, yang dapat menyulitkan penulisan kode yang bersih dan dapat dipelihara. Dalam pos blog ini, kita akan mengeksplorasi masalah ini dan menyajikan solusi elegan untuk mengakses kontainer-kontainer ini secara generik.
Masalah
Saat Anda mencoba mengakses item dalam kontainer yang beragam ini, Anda dengan cepat menghadapi masalah. Dalam kelas Foo
Anda, Anda menginginkan satu iterator yang dapat berinteraksi dengan std::vector<int>
, std::list<int>
, dan daftar kustom Anda. Namun, karena semua kontainer ini mengembalikan jenis iterator yang berbeda, upaya Anda untuk menetapkan satu iterator akan menyebabkan konflik jenis.
Berikut adalah versi sederhana dari tantangan yang Anda hadapi:
class Foo {
public:
Foo() {
std::list<int> x;
std::vector<int> y;
custom_list<int> z;
iter = x.begin(); // ATAU
iter = y.begin(); // ATAU
iter = z.begin(); // Masalah: Jenis iterator yang berbeda
};
private:
std::iterator<int> iter; // Ini tidak akan berfungsi
};
Solusi
Untuk menyelesaikan masalah ini sambil menjaga kode Anda elegan dan dapat dikelola, kita dapat memanfaatkan konsep yang dikenal sebagai penghapusan jenis. Teknik ini memungkinkan kita untuk membuat antarmuka generik untuk iterator, memberikan cara yang seragam untuk mengakses item di berbagai jenis kontainer.
Langkah 1: Kelas Dasar Iterator
Kita akan mulai dengan mendefinisikan antarmuka dasar yang akan diwarisi oleh semua iterator. Ini memberikan pendekatan yang umum untuk berinteraksi dengan berbagai tipe iterator.
class IIterator {
public:
virtual ~IIterator() = default;
virtual int& operator*() = 0; // Operator dereferensi
virtual IIterator& operator++() = 0; // Operator increment
virtual bool operator!=(const IIterator& other) const = 0; // Operator perbandingan
};
Langkah 2: Implementasi untuk Setiap Jenis Kontainer
Selanjutnya, kita akan mengimplementasikan antarmuka ini untuk berbagai jenis kontainer.
Untuk std::vector
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;
}
};
Untuk std::list
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;
}
};
Untuk Daftar Kustom
Dengan asumsi daftar kustom Anda yang mendefinisikan iterator tersedia, Anda akan menerapkannya serupa seperti di bawah ini:
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;
}
};
Langkah 3: Menggunakan Iterator dalam Foo
Sekarang, di kelas Foo
Anda, Anda dapat mempertahankan satu jenis pointer ke kelas dasar IIterator
untuk menangani jenis kontainer apa pun.
class Foo {
public:
Foo() {
std::list<int> x;
std::vector<int> y;
custom_list<int> z;
IIterator* iter;
// Mari kita anggap Anda memiliki instance dari setiap kontainer
iter = new VectorIterator(y.begin());
// ATAU
iter = new ListIterator(x.begin());
// ATAU
iter = new CustomListIterator(z.begin());
// Anda sekarang dapat menggunakan iter sebagai iterator yang seragam
};
};
Kesimpulan
Dengan memanfaatkan penghapusan jenis melalui antarmuka iterator yang umum, kita telah menyediakan cara elegan untuk memanipulasi berbagai jenis kontainer di C++. Ini memungkinkan kode yang lebih bersih dan lebih mudah dipelihara sambil menghindari masalah dalam mengelola beberapa jenis iterator.
Untuk eksplorasi lebih lanjut tentang topik ini, pertimbangkan untuk membaca beberapa artikel yang menarik:
- Memberikan Kelas Dasar kepada Iterator STL
- Penghapusan Jenis untuk Iterator C++
- Referensi Kelas any_iterator
Solusi ini tidak hanya meningkatkan keterampilan C++ Anda tetapi juga membantu menciptakan struktur kode yang serbaguna dan dapat digunakan kembali yang dapat menangani berbagai jenis kontainer dengan mulus.