الوصول إلى فئة القوالب المشتقة إلى بيانات الأعضاء على مستوى الأساس

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

سؤال

هذا السؤال هو تعزيز واحد طلب في هذا الموضوع.

باستخدام تعريفات الطبقة التالية:

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // This doesn't work - compiler error is: error: ‘_foo_arg’ was not declared in this scope
    std::cout << Bar<T>::_foo_arg << std::endl;   // This works!
}

عند الوصول إلى أعضاء الفصل الأساسي من فئة القالب، يبدو أنه يجب علي دائما تأهيل الأعضاء بشكل صريح باستخدام بناء جملة نمط القالب Bar<T>::_foo_arg. وبعد هل هناك طريقة لتجنب ذلك؟ هل يمكن تشغيل عبارة / توجيه "استخدام" في طريقة فئة القالب لتبسيط التعليمات البرمجية؟

يحرر:

تم حل مشكلة النطاق عن طريق تصفية المتغير مع بناء الجملة هذا.

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

المحلول

يمكنك استخدام this-> للتأكد من أنك تشير إلى عضو في الفصل:

void Bar<T>::BarFunc () {
    std::cout << this->_foo_arg << std::endl;
}

بدلا من ذلك، يمكنك أيضا استخدام "using"في الطريقة:

void Bar<T>::BarFunc () {
    using Bar<T>::_foo_arg;             // Might not work in g++, IIRC
    std::cout << _foo_arg << std::endl;
}

هذا يجعل من الواضح أن اسم العضو يعتمد على معلمات القالب بحيث يبحث عن تعريف هذا الاسم في الأماكن الصحيحة. لمزيد من المعلومات ترى أيضا هذا الدخول في الأسئلة الشائعة C ++ لايت.

نصائح أخرى

هنا الفئة الأساسية ليست فئة قاعدة غير مقبرة (والتي تعني واحدة ذات نوع كامل يمكن تحديدها دون معرفة حجج القالب) و _foo_arg هو اسم غير مناسب. تقول C ++ القياسية أن الأسماء غير المرئية لا يتم النظر إليها في الفصول الأساسية التابعة.

لتصحيح الكود، يكفي لجعل الاسم _foo_arg يعتمد ذلك لأن الأسماء المعالين يمكن البحث عنها فقط في وقت إنشاء مثيل، وفي ذلك الوقت التخصص الأساسي الدقيق الذي يجب استكشافه سيكون معروفا. علي سبيل المثال:

// solution#1
std::cout << this->_foo_arg << std::endl;

يتكون بديل في إدخال تبعية باستخدام اسم مؤهل:

// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;

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

ويمكنك إحضار اسما من فئة أساسية تعتمد في الفئة المشتقة مرة واحدة using:

// solution#3
template <class T>
class Bar : public Foo<T> {
public:
    ...
    void BarFunc ();
private:
    using Foo<T>::_foo_arg;
};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // works
}

يبدو أنه يعمل بشكل جيد في Visual C ++ 2008. لقد أضفت بعض التعريفات الدمية للأنواع التي ذكرتها ولكن لم تعط أي مصدر ل. الباقي هو بالضبط كما وضعت عليه. ثم وظيفة رئيسية لفرض BarFunc أن تكون مثيل لها ودعا.

#include <iostream>

class streamable {};
std::ostream &operator<<(std::ostream &os, streamable &s) { return os; }

class foo_arg_t : public streamable {};
class a_arg_t : public streamable {};
class b_arg_t : public streamable  {};

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl; 
    std::cout << Bar<T>::_foo_arg << std::endl;   
}

int main()
{
    Bar<a_arg_t> *b = new Bar<a_arg_t>(foo_arg_t(), a_arg_t());
    b->BarFunc();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top