2011-10-26 7 views
32

जबकि मैं क्यूटी के स्रोत कोड की जांच करता हूं, मैंने देखा कि ट्रॉल्टेक लोग विनाशक पर एक क्षेत्र तक पहुंचने के लिए स्पष्ट रूप से this कीवर्ड का उपयोग करते हैं।एक टेम्पलेटेड व्युत्पन्न कक्षा में, मुझे सदस्य वर्ग के अंदर "यह->" के साथ बेस क्लास सदस्य नामों को अर्हता प्राप्त करने की आवश्यकता क्यों है?

inline ~QScopedPointer() 
{ 
    T *oldD = this->d; 
    Cleanup::cleanup(oldD); 
    this->d = 0; 
} 

तो, इस उपयोग का क्या मतलब है? क्या कोई फायदा है?

संपादित करें: जो लोग इस सवाल को बंद करने के लिए मतदान के लिए, मुझे लगता है कि इस प्रयोग के कुछ वर्ग विरासत मामलों

के लिए है QScopedPointer class परिभाषा का एक हिस्सा है:

template <typename T, typename Cleanup = QScopedPointerDeleter<T> > 
class QScopedPointer 

उत्तर

39

सी ++ जवाब (सामान्य जवाब)

एक टेम्पलेट आधार वर्ग के साथ एक टेम्पलेट वर्ग Derived पर विचार करें:

template <typename T> 
class Base { 
public: 
    int d; 
}; 

template <typename T> 
class Derived : public Base<T> { 
    void f() { 
     this->d = 0; 
    } 
}; 

this टाइप Derived<T> है, एक प्रकार जो T पर निर्भर करता है। तो this पर एक निर्भर प्रकार है। तो this->dd एक आश्रित नाम बनाता है। आश्रित नाम टेम्पलेट परिभाषा के संदर्भ में गैर-निर्भर नामों के रूप में और तत्काल के संदर्भ में देखा जाता है।

this-> के बिना, d नाम केवल गैर-निर्भर नाम के रूप में देखा जाएगा, और नहीं मिला।

template <typename T> 
class Derived : public Base<T> { 
    using Base::d; 
    void f() { 
     d = 0; 
    } 
}; 

Qanswer (विशिष्ट जवाब)

d एक member of QScopedPointer है:

एक अन्य समाधान टेम्पलेट परिभाषा अपने आप में d घोषित करने के लिए है। यह विरासत में सदस्य नहीं है। this-> यहां जरूरी नहीं है।

OTOH, QScopedArrayPointer is a template class and d is an inherited member of a template base class:

template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> > 
class QScopedArrayPointer : public QScopedPointer<T, Cleanup> 

तो this-> आवश्यक here है:

inline T &operator[](int i) 
{ 
    return this->d[i]; 
} 

यह देखना है कि यह आसान है बस हर जगह this-> डाल करने के लिए आसान है।

कारण

समझे मुझे लगता है कि यही कारण है कि नाम देखा-अप गैर निर्भर आधार वर्ग में नहीं बल्कि निर्भर आधार वर्ग में कर रहे हैं यह सब सी ++ उपयोगकर्ताओं के लिए स्पष्ट नहीं है:

class Base0 { 
public: 
    int nd; 
}; 

template <typename T> 
class Derived2 : 
     public Base0, // non-dependent base 
     public Base<T> { // dependent base 
    void f() { 
     nd; // Base0::b 
     d; // lookup of "d" finds nothing 

     f (this); // lookup of "f" finds nothing 
        // will find "f" later 
    } 
}; 

नहीं है "मानक कहता है" के बगल में एक कारण: टेम्पलेट्स में बाध्यकारी तरीके का नाम काम करता है।

टेम्पलेट्स का नाम हो सकता है जो टेम्पलेट तत्काल हो जाने पर देर से बाध्य हो: उदाहरण के लिए ff (this) में। Derived2::f() परिभाषा के बिंदु पर, कंपाइलर द्वारा ज्ञात कोई चर, फ़ंक्शन या प्रकार नाम f नहीं है।ज्ञात इकाइयों का सेट f इस बिंदु पर खाली हो सकता है। यह कोई समस्या नहीं है क्योंकि संकलक जानता है कि यह फ़ंक्शन नाम, या टेम्पलेट फ़ंक्शन नाम के रूप में बाद में f लुकअप करेगा।

ओटीओएच, संकलक को पता नहीं है कि d के साथ क्या करना है; यह एक (बुलाया) समारोह नाम नहीं है। गैर-(बुलाए गए) कार्यों के नाम पर देर से बाध्यकारी करने का कोई तरीका नहीं है।

अब, यह सब संकलन-समय टेम्पलेट बहुरूपता के प्राथमिक ज्ञान की तरह प्रतीत हो सकता है। असली सवाल यह प्रतीत होता है: dBase<T>::d पर टेम्पलेट परिभाषा समय पर क्यों नहीं है? Base<T> घोषित किया जाता है, लेकिन परिभाषित नहीं:

असली मुद्दा टेम्पलेट परिभाषा समय कोई Base<T>::d है कि वहाँ, कोई पूरा प्रकार Base<T> उस समय है, क्योंकि है! आप पूछ सकते हैं: क्या इस बारे में:

template <typename T> 
class Base { 
public: 
    int d; 
}; 

यह एक पूर्ण प्रकार की परिभाषा की तरह लग रहा है! संकलक को

template <typename T> 
class Base; 

:

वास्तव में, इन्स्टेन्शियशन जब तक, यह अधिक की तरह दिखता है। क्लास टेम्पलेट में एक नाम नहीं देखा जा सकता है! लेकिन केवल एक टेम्पलेट विशेषज्ञता (तत्काल) में। टेम्पलेट टेम्पलेट विशेषज्ञता बनाने के लिए एक कारखाना है, एक टेम्पलेट टेम्पलेट विशेषज्ञता का एक सेट नहीं है। संकलक dBase<T> में किसी विशेष प्रकार T के लिए देख सकता है, लेकिन यह कक्षा कक्षा टेम्पलेट Base में नहीं देख सकता है। एक प्रकार तक T निर्धारित किया गया है, Base<T>::d अमूर्त Base<T>::d बनी हुई है; केवल T टाइप करें, Base<T>::dint प्रकार के एक चर को संदर्भित करना प्रारंभ करें।

इस का परिणाम यह है वर्ग टेम्पलेटDerived2 एक पूरा आधार वर्ग Base0 लेकिन एक अधूरी (आगे घोषित) आधार वर्ग Base है। केवल ज्ञात प्रकार T के लिए, "टेम्पलेट क्लास" (क्लास टेम्पलेट की विशेषज्ञता) Derived2<T> में किसी भी सामान्य श्रेणी की तरह पूर्ण आधार कक्षाएं हैं।

अब आप देख सकते हैं कि:

template <typename T> 
class Derived : public Base<T> 

वास्तव में एक आधार वर्ग विनिर्देश टेम्पलेट (एक कारखाने आधार वर्ग विनिर्देशों बनाने के लिए) है कि एक टेम्पलेट के अंदर एक आधार वर्ग विनिर्देश से अलग नियमों का पालन करती है।

टिप्पणी: पाठक ने देखा होगा कि मैंने स्पष्टीकरण के अंत में कुछ वाक्यांश बनाए हैं। dDerived<T> में एक योग्य नाम है यहां, और Derived<T> निर्भर है के बाद से T टेम्पलेट पैरामीटर है:

यह बहुत अलग है। एक योग्य नाम देर से बाध्य हो सकता है भले ही यह एक (नामित) फ़ंक्शन नाम न हो।

फिर भी एक और उपाय है:

template <typename T> 
class Derived : public Base<T> { 
    void f() { 
     Derived::d = 0; // qualified name 
    } 
}; 

यह बराबर है।

यदि आपको लगता है कि Derived<T> की परिभाषा के अंदर, Derived<T> का उपचार कभी-कभी ज्ञात पूर्ण वर्ग के रूप में और अनजान वर्ग के रूप में अज्ञात वर्ग के रूप में कुछ अन्य बार, ठीक है, तो आप सही हैं।

+0

** मॉडरेटर नोट ** इस उत्तर के तहत _Comments शुद्ध कर दिए गए हैं क्योंकि वे शुद्ध शोर में खराब हो गए हैं। विस्तारित चर्चाओं के लिए कृपया [चैट] का उपयोग करें और नागरिक बने रहें ._ –

1

मुझे लगता है कि यह क्लीनअप() दिनचर्या के अधिभारित उपयोग से संबंधित है। पास किया जा रहा प्रकार स्पष्ट रूप से टेम्पलेट प्रकार टी द्वारा नियंत्रित किया जाता है, जो बदले में क्लीनअप() का ओवरलोडेड संस्करण नियंत्रित कर सकता है।

संबंधित मुद्दे