2011-08-25 8 views
12

लंबे शीर्षक के लिए खेद है, लेकिन मैं विशिष्ट होना चाहता था। मैं काम करने के लिए निम्न कोड की उम्मीद है, लेकिन यह नहीं है और मैं समझ नहीं करता है क्यों:/किसी व्युत्पन्न वर्ग के लिए पॉइंटर को बेस क्लास के पॉइंटर के संदर्भ की अपेक्षा करने वाले फ़ंक्शन को कैसे पास नहीं किया जा सकता है?

#include <cstdio> 
#include <cassert> 

class UniquePointer 
{ 
public: 
    void Dispose() 
    { 
     delete this; 
    } 

    friend void SafeDispose(UniquePointer*& p) 
    { 
     if (p != NULL) 
     { 
      p->Dispose(); 
      p = NULL; 
     } 
    } 
protected: 
    UniquePointer() { } 
    UniquePointer(const UniquePointer&) { } 
    virtual ~UniquePointer() { } 
}; 

class Building : public UniquePointer 
{ 
public: 
    Building() 
    : mType(0) 
    {} 
    void SetBuildingType(int type) { mType = type; } 
    int GetBuildingType() const { return mType; } 
protected: 
    virtual ~Building() { } 
    int mType; 
}; 

void Foo() 
{ 
    Building* b = new Building(); 
    b->SetBuildingType(5); 
    int a = b->GetBuildingType(); 
    SafeDispose(b);  // error C2664: 'SafeDispose' : cannot convert parameter 1 from 'Building *' to 'UniquePointer *&' 
    b->Dispose(); 
} 

int main(int argc, char* argv[]) 
{ 
    Foo(); 
    return 0; 
} 
+1

ध्यान दें कि आप जो भी करने की कोशिश कर रहे हैं उसके बारे में "सुरक्षित" कुछ भी नहीं है। यदि 'बी'' NULL' पर सेट किया गया है तो 'b-> निपटान(); 'व्यवहार का कारण बनता है जो कि अनिर्धारित है जैसे' b' किसी हटाए गए ऑब्जेक्ट को इंगित करता है। –

+0

@ चार्ल्स: संपादित, समीक्षा के लिए प्रतीक्षा कर रहा है। यह बग एक प्रश्न का हिस्सा नहीं है, है ना? –

+0

इसके अलावा, 'निपटान' के बाद से एक मित्र होने के लिए 'सुरक्षित डिस्प्ले' की आवश्यकता नहीं है। –

उत्तर

42

कल्पना कीजिए यह कानूनी थे। तो फिर तुम इस तरह कोड लिख सकते हैं:

class Animal : public UniquePointer 
{ 
}; 

void Transmogrify(UniquePointer*& p) 
{ 
    p = new Animal(); 
} 

void Foo() 
{ 
    Building* b = nullptr; 
    Transmogrify(b); 
    b->SetBuildingType(0); // crash 
} 

का निरीक्षण करें कि आप एक डाली की आवश्यकता होती है या एक संकलक त्रुटि को ऊपर उठाने के बिना प्रकार प्रणाली (यदि आप एक पशु जहां एक भवन होना चाहिए डाल) का उल्लंघन किया है।

+0

मैं तुम्हारा बिंदु देखता हूं। कारण मैं पॉइंटर का संदर्भ चाहता था कि वह पॉइंटर को न्यूल पर सेट करने में सक्षम हो, लेकिन मुझे स्पष्ट रूप से सभी दुष्प्रभावों को याद किया गया था। –

3

यह अनुमति नहीं है क्योंकि अगर यह थे आप निम्न कर सकता है:

friend void SafeDispose(UniquePointer*& p) 
{ 
    p = new UniquePointer(); 
} 


Building* building; 
SafeDispose(building) 
//building points to a UniquePointer not a Building. 

मैं आसपास काम लगता है कि एक टेम्पलेट समारोह होगा।

+0

सिवाय इसके कि आप अद्वितीय सूचक को तुरंत चालू नहीं कर सकते हैं, इसे उप-वर्गीकृत किया जाना चाहिए। लेकिन मैं तुम्हारा मुद्दा देखता हूं। –

6

मुझे नहीं लगता कि यह आपके द्वारा डिज़ाइन किए गए तरीके से काम करना संभव है। इसके बजाय, निम्न प्रयास करें:

template <typename T> 
void SafeDispose(T * & p) 
{ 
    if (p != NULL) 
    { 
     p->Dispose(); 
     p = NULL; 
    } 
} 

class UniquePointer 
{ 
public: 
    void Dispose() 
    { 
     delete this; 
    } 

protected: 
    UniquePointer() { } 
    UniquePointer(const UniquePointer&) { } 
    virtual ~UniquePointer() { } 
}; 
+0

मुझे आपका समाधान पसंद है, वास्तव में आपको यह कहना चाहिए कि ऐसा करने के लिए ऐसा क्यों संभव नहीं है जैसा मैंने किया था, यह मेरा स्वीकार्य उत्तर होगा। –

0

मुझे लगता है कि अपने SafeDispose शायद और अधिक की तरह दिखना चाहिए:

friend void SafeDispose(UniquePointer** p) ... 

ताकि इसे लागू करने की में

SafeDispose(&(UniquePointer*)b); 

का उपयोग कर तो यह इस तरह से काम करना चाहिए।

लेकिन अपने अगले बयान

b->Dispose(); 

टूट जाएगा कारण ख अब, शून्य होना चाहिए कारण यह आपके SafeDispose विधि द्वारा निपटारा किया गया है और सेट शून्य करने के लिए।

+0

लेकिन '& b' प्रकार 'बिल्डिंग **' का एक रैल्यू है जिसे आप 'अनन्य पॉइंटर **' लेते हुए एक समारोह में पास नहीं कर सकते हैं, जो कि बहुत ही समान कारणों से है कि आप 'बिल्डिंग *' को गैर- -कॉन्स्ट 'अनन्य पॉइंटर * और '। –

+0

इसे इंगित करने के लिए धन्यवाद। एक कास्ट जोड़ना शायद इस मुद्दे को ठीक करेगा? (अद्यतन नमूना कोड)। फिर मुझे लगता है कि विल्क्स उत्तर (टेम्पलेट का उपयोग करके) अधिक समझ में आता है। –

+1

नहीं, एक कलाकार इस मुद्दे को ठीक नहीं करता है जो इसे एक नया बनाता है। कास्ट सूचक को परिवर्तित करता है लेकिन कास्ट का नतीजा एक रावल है और आप तब एक रावल्यू का पता नहीं ले सकते हैं। –

1

अपने प्रश्न के शीर्षक का उत्तर देने के लिए, आप किसी व्युत्पन्न क्लास इंस्टेंस पर आधार के लिए एक गैर-कॉन्स्ट संदर्भ को बाध्य नहीं कर सकते हैं क्योंकि आप उस संदर्भ को एक मूल उदाहरण में पॉइंटर पर सेट कर सकते हैं जो व्युत्पन्न नहीं है। इस समारोह पर विचार करें:

void Renew(UniquePointer *& p) { 
    delete p; 
    p = new UniquePointer(); 
} 

अगर आप इसे Building के लिए सूचक आप एक UniquePointer उदाहरण के लिए बात करने के लिए गलत तरीके से यह स्थापित करने के लिए सक्षम हो जाएगा दे सकते हैं।

जैसा कि पहले से ही सुझाव दिया गया है कि समाधान एक सादे सूचक में आपका संदर्भ बदलना है। न केवल यह आपकी समस्या हल करता है, बल्कि यह SafeDispose() का बेहतर कार्यान्वयन भी है; जैसा कि आपने लिखा है इस फ़ंक्शन ने झूठा विचार दिया है कि आप हमेशा अपने UniquePointer उदाहरणों पर 0 पर सेट करेंगे। लेकिन क्या होगा अगर किसी ने लिखा है (UniquePointer निर्माता मानते हुए सादगी के लिए सार्वजनिक किया गया था):

UniquePointer *p1 = new UniquePointer(); 
UniquePointer *p2 = p1; 
SafeDispose(p1); 

वे अपने UniquePointer रों के सभी उम्मीद होती है ठीक से, का ध्यान रखा जाना करने के लिए जब p2 वास्तव में अवैध है।

+0

मैं शायद जो कुछ भी किया उसके मुकाबले सबकुछ बेहतर नाम दे सकता था। मेरा इरादा पॉइंटर को न्यूल पर सेट करने के लिए सुरक्षित है और न्यूल की जांच करें, लेकिन मैंने इस तथ्य पर विचार नहीं किया कि कैली में सूचक की एक प्रति हो सकती है। लेकिन यह ध्यान रखना महत्वपूर्ण है कि कोई भी साझाकरण नहीं है, मुझे Google की कोडिंग शैली पढ़ने के बाद "गायन स्वामित्व" प्रणाली में रूचि थी। –

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