البحث عن طريقة عامة للوصول إلى حاويات متنوعة في C++
في C++ الحديثة، يواجه المطورون تحديًا شائعًا يتمثل في تكرار أنواع الحاويات المختلفة بشكل موحد. تخيل أنك تمتلك العديد من الحاويات: std::vector
القياسية، و std::list
، وقائمة مخصصة. كل حاوية لديها نوع مكرر فريد خاص بها، مما قد يجعل كتابة كود نظيف وسهل الصيانة أمرًا صعبًا. في هذه التدوينة، سوف نستكشف هذه المشكلة ونقدم حلاً أنيقًا للوصول إلى هذه الحاويات بشكل عام.
المشكلة
عندما تحاول الوصول إلى العناصر في هذه الحاويات المتنوعة، ستواجه مشكلة بسرعة. في صفك Foo
، تريد مكررًا واحدًا يمكنه التفاعل مع std::vector<int>
، و std::list<int>
، وقائمتك المخصصة. ومع ذلك، نظرًا لأن جميع هذه الحاويات تعيد أنواع مكررات مختلفة، فإن محاولاتك لتعيين مكرر واحد ستؤدي إلى تعارضات في الأنواع.
إليك نسخة مبسطة من التحدي الذي تواجهه:
class Foo {
public:
Foo() {
std::list<int> x;
std::vector<int> y;
custom_list<int> z;
iter = x.begin(); // أو
iter = y.begin(); // أو
iter = z.begin(); // مشكلة: أنواع مكررات مختلفة
};
private:
std::iterator<int> iter; // هذا لن يعمل
};
الحل
لحل هذه المشكلة مع الحفاظ على كودك أنيقًا وقابلًا للإدارة، يمكننا الاستفادة من مفهوم يُعرف باسم تلاشي النوع. تمكننا هذه التقنية من إنشاء واجهة عامة للمكررات، مما يوفر طريقة موحدة للوصول إلى العناصر عبر أنواع الحاويات المختلفة.
الخطوة 1: واجهة مكرر أساسية
سنبدأ بتعريف واجهة أساسية ستقوم جميع المكررات بالوراثة منها. وهذا يوفر طريقة مشتركة للتفاعل مع أنواع المكررات المختلفة.
class IIterator {
public:
virtual ~IIterator() = default;
virtual int& operator*() = 0; // عامل فك الإشارة
virtual IIterator& operator++() = 0; // عامل الزيادة
virtual bool operator!=(const IIterator& other) const = 0; // عامل المقارنة
};
الخطوة 2: تنفيذ لكل نوع حاوية
بعد ذلك، سنقوم بتنفيذ هذه الواجهة لأنواع الحاويات المختلفة.
لـ 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;
}
};
لـ 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;
}
};
لقائمة مخصصة
بالافتراض أن لديك قائمة مخصصة تعرف مكررًا، سوف تقوم بتنفيذ ذلك بنفس الطريقة كما يلي:
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;
}
};
الخطوة 3: استخدام المكررات في Foo
الآن، في صفك Foo
، يمكنك الاحتفاظ بنوع واحد من المؤشر إلى الصف الأساسي IIterator
للتعامل مع أي من أنواع الحاويات.
class Foo {
public:
Foo() {
std::list<int> x;
std::vector<int> y;
custom_list<int> z;
IIterator* iter;
// لنفترض أن لديك مثيلات من كل حاوية
iter = new VectorIterator(y.begin());
// أو
iter = new ListIterator(x.begin());
// أو
iter = new CustomListIterator(z.begin());
// يمكنك الآن استخدام iter كمكرر موحد
};
};
الخاتمة
من خلال الاستفادة من تلاشي النوع من خلال واجهة مكرر شائعة، لقد قدمنا طريقة أنيقة للتلاعب بأنواع الحاويات المختلفة في C++. وهذا يوفر كودًا أكثر نظافة وقابلية للصيانة ويفيد في تجنب صداع إدارة أنواع مكررات متعددة.
لمزيد من الاستكشاف حول هذا الموضوع، يمكنك الاطلاع على بعض المقالات المفيدة:
هذا الحل لا يعزز مهاراتك في C++ فحسب، بل يساعد أيضًا في إنشاء هياكل تعليمية متعددة الاستخدامات وقابلة لإعادة الاستخدام يمكنها التعامل مع أنواع الحاويات المختلفة بسلاسة.