سؤال

ما هي العلاقة بين استخدام الدالات الظاهرية وآليات الميراث C ++ مقابل استخدام القوالب وشيء من هذا القبيل المفاهيم دفعة؟

ويبدو أن هناك تماما تداخل ما هو ممكن. وهي، يبدو أن من الممكن لتحقيق سلوك متعدد الأشكال مع أي من الطريقتين. لذلك، عندما لا يعقل أن يفضل أحدهما على الآخر؟

والسبب أحمل هذا الأمر لأن لدي حاوية قالب، حيث الحاويات أنفسهم لها علاقة هرمية. وأود أن أكتب الخوارزميات التي تستخدم هذه الحاويات دون أي اهتمام حول أي حاوية محددة هو عليه. أيضا، فإن بعض الخوارزميات الاستفادة من معرفة أن نوع القالب راض بعض المفاهيم (المقارنة، على سبيل المثال).

وهكذا، من جهة، أريد حاويات للتصرف polymorphicly. من جهة أخرى، لا يزال لدي لاستخدام المفاهيم إذا أريد لتنفيذ بعض الخوارزميات بشكل صحيح. ما هو مطور صغار أن تفعل؟

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

المحلول

وأعتقد المفاهيم كنوع من الفوقية واجهة. هم تصنيف أنواع بعد قدراتهم. وC ++ المقبل إمدادات نسخة المفاهيم الأم. أنا لم يفهم حتى جئت عبر مفاهيم C ++ 1X وكيف تسمح وضع أنواع مختلفة من بعد لا علاقة لها معا. تخيل لديك واجهة Range. يمكنك نموذج أنه مع بطريقتين. واحد هو العلاقة النوع الفرعي :

class Range {
    virtual Iterator * begin() = 0;
    virtual Iterator * end() = 0;

    virtual size_t size() = 0;
};

وبطبيعة الحال، كل فئة مشتقة من أن تنفذ واجهة المدى، ويمكن استخدامها مع مهامكم. لكننا نرى الآن أنها محدودة. ماذا عن مجموعة؟ هو النطاق أيضا!

T t[N];

begin() => t
end() => t + size()
size() => N

للأسف، لا يمكنك استخلاص مجموعة من تلك الفئة نطاق تنفيذ تلك الواجهة. أنت بحاجة إلى طريقة إضافية (<م> الحمولة الزائدة ). وماذا عن حاويات طرف ثالث؟ يمكن للمستخدم من مكتبتك قد ترغب في استخدام عبواتها مع مهامكم. لكنه لا يستطيع تغيير تعريف عبواتها. هنا، مفاهيم تأتي في اللعبة:

auto concept Range<typename T> {
    typename iterator;
    iterator T::begin();
    iterator T::end();
    size_t T::size();
}

والآن، ويقول لك شيئا عن العمليات المدعومة من بعض النوع الذي يمكن أن تتحقق إذا T لديها وظائف عضو المناسبة. في مكتبتك، أن تكتب وظيفة عامة. هذا يسمح لك قبول أي نوع <م> طالما أنه يدعم العمليات المطلوبة:

template<Range R>
void assign(R const& r) {
    ... iterate from r.begin() to r.end(). 
}

وانها نوع كبير من إحلال . أي نوع تناسب مشروع القانون الذي تتمسك مفهوم، وليس فقط تلك الأنواع التي تنفذ بنشاط بعض اجهة. و++ القياسية C القادم يذهب أبعد من ذلك: فهو يحدد مفهوم Container التي من شأنها أن يكون لائقا من صفائف عادي (من شيء كليد <م> خريطة مفهوم أن يعرف كيف أن بعض نوع يناسب بعض مفهوم) وغيرها، <م> القائمة حاوية قياسية.

<اقتباس فقرة>   

والسبب أحمل هذا الأمر لأن لدي حاوية قالب، حيث الحاويات أنفسهم لها علاقة هرمية. وأود أن أكتب الخوارزميات التي تستخدم هذه الحاويات دون أي اهتمام حول أي حاوية محددة هو عليه. أيضا، فإن بعض الخوارزميات الاستفادة من معرفة أن نوع القالب راض بعض المفاهيم (المقارنة، على سبيل المثال).

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

// tag types for the comparator cagetory
struct not_comparable { };
struct basic_comparable : not_comparable { };

template<typename T>
class MyVector : public BasicContainer<T> {
    typedef basic_comparable comparator_kind;
};

/* Container concept */
T::comparator_kind: comparator category

وانها طريقة بسيطة معقولة للقيام بذلك، في الواقع. الآن يمكنك استدعاء وظيفة، وسوف تحيل إلى التنفيذ الصحيح.

template<typename Container>
void takesAdvantage(Container const& c) {
    takesAdvantageOfCompare(c, typename Container::comparator_kind());
}

// implementation for basic_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, basic_comparable) {
    ...
}

// implementation for not_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, not_comparable) {
    ...
}

وهناك تقنيات مختلفة في الواقع والتي يمكن استخدامها لتنفيذ ذلك. وهناك طريقة أخرى لاستخدام boost::enable_if لتمكين أو تعطيل تطبيقات مختلفة في كل مرة.

نصائح أخرى

نعم، سلوك متعدد الأشكال هو ممكن مع كل من الآليات. في الواقع، وكلاهما <م> دعا تعدد الأشكال أيضا.

وظائف افتراضية تعطيك التعدد الحيوي (لأنه قرر في وقت التشغيل)، في حين قوالب تعطيك تعدد الأشكال ثابت (يتقرر كل شيء في الترجمة من الوقت).

والتي يجب أن تجيب على السؤال الذي تفضل كذلك. كلما أمكن ذلك، ويفضل أن نقل العمل إلى وقت التحويل البرمجي. حتى عندما كنت يمكن أن تفلت من ذلك، استخدام قوالب لحل الاحتياجات تعدد الأشكال الخاصة بك. وعندما لم يكن ذلك ممكنا (لأنك تحتاج إلى استخدام معلومات نوع وقت، لأن أنواع الدقيق ليست معروفة في الترجمة من الوقت)، يرتد إلى تعدد الأشكال الحيوية.

(وبطبيعة الحال قد تكون هناك أسباب أخرى لتفضيل واحدة أو أخرى. وعلى وجه الخصوص، قوالب تتطلب منك نقل الكثير من التعليمات البرمجية لرأس الملفات التي قد تكون أو لا تكون مشكلة، وسرعة تجميع يميل إلى المعاناة التي أيضا قد يكون أو لا يكون مشكلة.)

وإذا كان من الممكن اتخاذ قرار في الترجمة من الوقت، استخدام القوالب. على خلاف ذلك استخدام الميراث وظائف افتراضية.

في هذه الحالة المحددة يمكنك أن تفعل شيئا مثل

template<typename T>
class ContainerBase{};

template<typename T>
class ContainerDerived : public ContainerBase<T> {};

وبما أن كل "الحاويات" نوع فريد من نوعه لكل نوع القالب، وليس هناك وظائف العقل عضو من كل نوع الحاوية لا يمكن المتخصصة في الصفات نوع قالب ل.

وكمثال بسيط من الفرق بين الترجمة الوقت ووقت التشغيل التعدد النظر في التعليمة البرمجية التالية:

template<typename tType>
struct compileTimePolymorphism
{ };

// compile time polymorphism,
// you can describe a behavior on some object type
// through the template, but you cannot interchange 
// the templates
compileTimePolymorphism<int> l_intTemplate;
compileTimePolymorphism<float> l_floatTemplate;
compileTimePolymorphism *l_templatePointer; // ???? impossible

struct A {};
struct B : public A{};
struct C : public A{};

// runtime polymorphism 
// you can interchange objects of different type
// by treating them like the parent
B l_B;
C l_C:
A *l_A = &l_B;
l_A = &l_C;

وترجمة لمرة والتعدد هو حل جيد عندما يعتمد سلوك كائن واحد على بعض وجوه الآخرين. وقت التشغيل تعدد الأشكال ضروري حيث يحتاج سلوك كائن إلى تغيير.

والاثنان يمكن الجمع عن طريق تحديد القالب الذي هو متعدد الأشكال:

template<typename tType>
struct myContainer : public tType
{};

والسؤال بعد ذلك حيث يحتاج سلوك حاوية لتغيير (وقت التشغيل تعدد الأشكال)، وحيث يعتمد السلوك على الكائنات أنه يحتوي على (تجميع وقت تعدد الأشكال).

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