الحصول على المتجه<مشتق*> في دالة تتوقع المتجه<Base*>

StackOverflow https://stackoverflow.com/questions/114819

  •  02-07-2019
  •  | 
  •  

سؤال

النظر في هذه الفئات.

class Base
{
   ...
};

class Derived : public Base
{
   ...
};

هذه الوظيفة

void BaseFoo( std::vector<Base*>vec )
{
    ...
}

وأخيرا ناقلات بلدي

std::vector<Derived*>derived;

أريد أن أمر derived لتعمل BaseFoo, لكن المترجم لا يسمح لي بذلك.كيف يمكنني حل هذه المشكلة دون نسخ المتجه بالكامل إلى ملف a std::vector<Base*>?

هل كانت مفيدة؟

المحلول

vector<Base*> و vector<Derived*> هي أنواع غير ذات صلة، لذلك لا يمكنك القيام بذلك.تم شرح ذلك في الأسئلة الشائعة الخاصة بـ C++ هنا.

تحتاج إلى تغيير المتغير الخاص بك من a vector<Derived*> إلى أ vector<Base*> وإدراج Derived الكائنات فيه.

وأيضا لتجنب النسخ vector بدون داعٍ، يجب عليك تمريرها عن طريق مرجع ثابت، وليس عن طريق القيمة:

void BaseFoo( const std::vector<Base*>& vec )
{
    ...
}

أخيرًا، لتجنب تسرب الذاكرة، وجعل استثناءات التعليمات البرمجية الخاصة بك آمنة، فكر في استخدام حاوية مصممة للتعامل مع الكائنات المخصصة للكومة، على سبيل المثال:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

بدلًا من ذلك، قم بتغيير المتجه ليحمل مؤشرًا ذكيًا بدلاً من استخدام المؤشرات الأولية:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

أو

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

في كل حالة، سوف تحتاج إلى تعديل الخاص بك BaseFoo تعمل وفقا لذلك.

نصائح أخرى

بدلاً من تمرير كائن الحاوية (vector<>)، تمر في begin و end التكرارات مثل بقية خوارزميات STL.سيتم تصميم الوظيفة التي تستقبلها، ولن يهم إذا قمت بتمرير مشتق* أو أساسي*.

تحدث هذه المشكلة في لغات البرمجة التي تحتوي على حاويات قابلة للتغيير.لا يمكنك تمرير كيس تفاح قابل للتغيير على أنه كيس فاكهة لأنك لا تستطيع التأكد من أن شخصًا آخر لم يضع ليمونًا في كيس الفاكهة هذا، وبعد ذلك لم يعد مؤهلاً ككيس تفاح.إذا لم يكن كيس التفاح قابلاً للتغيير، فسيكون من الجيد تمريره ككيس فاكهة.البحث عن التباين/التباين.

أحد الخيارات هو استخدام القالب

template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
 ...
}

العيب هو أن التنفيذ يجب أن يكون في الرأس وستحصل على القليل من التعليمات البرمجية.سينتهي بك الأمر بإنشاء وظائف مختلفة لكل نوع، لكن الرمز يظل كما هو.اعتمادًا على حالة الاستخدام، فهو حل سريع وقذر.

تحرير، يجب أن أشير إلى سبب حاجتنا إلى قالب هنا هو أننا نحاول كتابة نفس الكود للأنواع غير ذات الصلة كما لاحظت العديد من الملصقات الأخرى.تسمح لك القوالب بحل هذه المشكلات بالضبط.لقد قمت أيضًا بتحديثه لاستخدام مرجع const.يجب عليك أيضًا تمرير الكائنات "الثقيلة" مثل المتجه عن طريق مرجع ثابت عندما لا تحتاج إلى نسخة، وهو ما يكون دائمًا في الأساس.

بشكل عام، ستبدأ بحاوية من المؤشرات الأساسية، وليس العكس.

مع الأخذ مات برايس الإجابة من الأعلى، نظرًا لأنك تعرف مسبقًا الأنواع التي تريد استخدامها مع وظيفتك، يمكنك الإعلان عن قالب الوظيفة في ملف الرأس، ثم إضافة إنشاءات واضحة لتلك الأنواع:

// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);

// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
 ...
}

// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );

إذا كنت تتعامل مع مكتبة تابعة لجهة خارجية، وهذا هو أملك الوحيد، فيمكنك القيام بذلك:

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

وإلا قم بإصلاح الكود الخاص بك باستخدام أحد الاقتراحات الأخرى.

لو std::vector إذا دعمت ما تطلبه، فسيكون من الممكن هزيمة نظام النوع C++ دون استخدام أي قوالب (تحرير:يتحدث رابط ChrisN إلى الأسئلة الشائعة حول C++ Lite عن نفس المشكلة):

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

void pushStuff(std::vector<Base*>& vec) {
    vec.push_back(new Derived2);
    vec.push_back(new Base);
}

...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!

منذ الخاص بك BaseFoo() تأخذ الدالة المتجه من حيث القيمة، ولا يمكنها تعديل المتجه الأصلي الذي مررته، لذا فإن ما كتبته لن يكون ممكنًا.ولكن إذا كان الأمر يتطلب مرجعًا غير ثابت وتستخدمه reinterpret_cast<std::vector<Base*>&>() لتمرير الخاص بك std::vector<Derived*>, ، فقد لا تحصل على النتيجة التي تريدها، وقد يتعطل برنامجك.

دعم صفائف جافا الكتابة الفرعية المتغيرة, ، وهذا يتطلب جافا قم بإجراء فحص نوع وقت التشغيل في كل مرة تقوم فيها بتخزين قيمة في مصفوفة.وهذا أيضاً غير مرغوب فيه.

إنها أنواع غير ذات صلة - لا يمكنك ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top