2008-09-24 7 views
57

मैंने सी ++ में एक इंटरफ़ेस परिभाषित किया है, यानी एक वर्ग जिसमें केवल शुद्ध वर्चुअल फ़ंक्शन हैं।जीएनयू कंपाइलर चेतावनी "कक्षा में वर्चुअल फ़ंक्शंस हैं लेकिन गैर-आभासी विनाशक"

मैं स्पष्ट रूप से इंटरफ़ेस करने के लिए एक सूचक के माध्यम से वस्तु को हटाने के लिए इंटरफ़ेस के उपयोगकर्ताओं न करे करना चाहते हैं, तो मैं इंटरफेस के लिए एक सुरक्षित और गैर आभासी नाशक की घोषणा की, कुछ की तरह:

class ITest{ 
public: 
    virtual void doSomething() = 0; 

protected: 
    ~ITest(){} 
}; 

void someFunction(ITest * test){ 
    test->doSomething(); // ok 
    // deleting object is not allowed 
    // delete test; 
} 

जीएनयू संकलक मुझे यह कहते हुए एक चेतावनी देता है:

वर्ग 'ITest' आभासी कार्यों लेकिन गैर आभासी नाशक है

एक बार विनाशक संरक्षित होने के बाद, इसे आभासी या गैर-आभासी होने में क्या अंतर है?

क्या आपको लगता है कि इस चेतावनी को सुरक्षित रूप से अनदेखा या चुप किया जा सकता है?

उत्तर

64

यह कंपाइलर में कम या ज्यादा एक बग है। ध्यान दें कि कंपाइलर के हाल के संस्करणों में यह चेतावनी फेंक नहीं पाती है (कम से कम 4.3 में यह नहीं है)। विनाशक को संरक्षित किया जाना चाहिए और गैर-आभासी आपके मामले में पूरी तरह से वैध है।

इस विषय पर हर्ब सटर द्वारा उत्कृष्ट लेख के लिए here देखें। लेख से:

दिशानिर्देश # 4: एक बेस क्लास विनाशक या तो सार्वजनिक और आभासी, या संरक्षित और nonvirtual होना चाहिए।

+0

मेरा मानना ​​है कि यह केवल एक चेतावनी है - और उपर्युक्त मामला असाधारण है। सामान्यतः यदि आपके पास वर्चुअल फ़ंक्शंस हैं तो शायद आपके पास आभासी विनाशक भी होना चाहिए। –

+1

मैं मानता हूं कि यह एक मामूली बग है कि एक संरक्षित विनाशक की उपस्थिति में चेतावनी दबाने नहीं है। व्युत्पन्न वर्ग द्वारा हटाने का उल्लेख करने वाले अन्य उत्तरों मान्य हैं, लेकिन नियमित रूप से अनुपलब्ध वर्चुअल विनाशकों की तुलना में समस्याग्रस्त होने की संभावना बहुत कम है। –

+0

हर्ब के लेख के लिंक के लिए धन्यवाद! –

0

यदि विनाशक आभासी है तो यह सुनिश्चित करता है कि बेस क्लास विनाशक को सफाई करने के लिए भी कहा जाता है, अन्यथा कुछ लीक उस कोड से परिणाम प्राप्त कर सकते हैं। इसलिए आपको यह सुनिश्चित करना चाहिए कि कार्यक्रम में ऐसी कोई चेतावनी नहीं है (बिल्कुल कोई चेतावनी नहीं है)।

9

इस उत्तर पर कुछ टिप्पणियां मैंने दिए गए पहले के जवाब से संबंधित हैं, जो गलत था।

एक संरक्षित विनाशक का अर्थ है कि इसे केवल बेस क्लास से ही बुलाया जा सकता है, हटाए जाने के माध्यम से नहीं। इसका मतलब है कि एक आईटीएस्ट * सीधे हटाया नहीं जा सकता है, केवल एक व्युत्पन्न वर्ग कर सकते हैं। व्युत्पन्न वर्ग अच्छी तरह से एक आभासी विनाशक चाहता है। आपके कोड में कुछ भी गलत नहीं है।

हालांकि, चूंकि आप स्थानीय रूप से जीसीसी में चेतावनी को अक्षम नहीं कर सकते हैं, और आपके पास पहले से ही एक vtable है, तो आप वैसे भी विनाशक वर्चुअल को बनाने पर विचार कर सकते हैं। यह कार्यक्रम के लिए आपको 4 बाइट्स खर्च करेगा (प्रति वर्ग उदाहरण नहीं), अधिकतम। चूंकि आपने अपनी व्युत्पन्न कक्षा को वर्चुअल डॉटर दिया हो सकता है, इसलिए आप पाएंगे कि इससे आपको कुछ भी लागत नहीं है।

+1

मैं हमेशा आश्चर्य है कि विनाशक हमेशा वर्चुअल क्यों नहीं है ... – INS

+2

2 कारण। (1) आप केवल सी ++ में जो भी उपयोग करते हैं उसके लिए भुगतान करते हैं। यदि डीटीआर वर्चुअल था तो बहुत से वर्गों में असफल vtables होगा। (2) कुछ ढांचे (उदाहरण के लिए। कॉर्बा) मेरा मानना ​​है कि अब वर्तमान व्यवहार पर निर्भर हैं। –

+0

रिचर्ड और एयरसोर्स, मैंने उन टिप्पणियों को हटा दिया जो पिछले उत्तर को संदर्भित करते हैं। अब मुझे आपके उत्तर में कोई समस्या नहीं है और मैंने अपना प्रारंभिक -1 +1 में बदल दिया है ... –

0

यदि आपके पास ITest की विधियों में से एक कोड था जो delete स्वयं (एक बुरा विचार, लेकिन कानूनी) की कोशिश की गई, व्युत्पन्न वर्ग के विनाशक को नहीं बुलाया जाएगा। आपको अभी भी अपना विनाशक वर्चुअल बनाना चाहिए, भले ही आप बेस-क्लास पॉइंटर के माध्यम से व्युत्पन्न उदाहरण को हटाने का इरादा न रखें।

+0

नहीं, उसे नहीं करना चाहिए। इंटरफ़ेस का अनुबंध जिसे उन्होंने परिभाषित किया है वह यह है कि इंटरफ़ेस के उपयोगकर्ता इसे लागू करने वाले ऑब्जेक्ट्स के उदाहरणों को हटा नहीं सकते हैं। यह उन वस्तुओं के लिए एक आम पैटर्न है जो कारखाने के माध्यम से या संदर्भ गिनती के माध्यम से आवंटित और साफ किए जाते हैं ... (-1) –

4

यदि आप ऐसा करने का आग्रह करते हैं, तो आगे बढ़ें और -Wno-non-virtual-dtor को जीसीसी में पास करें। यह चेतावनी डिफ़ॉल्ट रूप से चालू नहीं प्रतीत होती है, इसलिए आपने इसे -Wall या -Weffc++ के साथ सक्षम कर दिया होगा। हालांकि, मुझे लगता है कि यह एक उपयोगी चेतावनी है, क्योंकि ज्यादातर स्थितियों में यह एक बग होगा।

2

यह एक इंटरफ़ेस वर्ग है, इसलिए यह उचित है कि आपको उस इंटरफ़ेस के माध्यम से उस इंटरफ़ेस को लागू करने वाली वस्तुओं को हटा नहीं देना चाहिए।इसका एक सामान्य मामला कारखाने द्वारा बनाई गई वस्तुओं के लिए एक इंटरफ़ेस है जिसे कारखाने में वापस किया जाना चाहिए। (ऑब्जेक्ट्स रखने से उनके कारखाने में पॉइंटर काफी महंगा हो सकता है)।

मैं इस अवलोकन से सहमत हूं कि जीसीसी चमक रहा है। इसके बजाए, जब आप किसी ITest * को हटाते हैं तो इसे केवल चेतावनी देना चाहिए। यही वह जगह है जहां असली खतरा झूठ बोलता है।

2

मेरा व्यक्तिगत विचार यह है कि आप सही काम कर रहे हैं और संकलक टूट गया है। यदि संभव हो तो मैं चेतावनी (स्थानीय रूप से फ़ाइल में इंटरफ़ेस को परिभाषित करता हूं) को अक्षम कर दूंगा,

मुझे लगता है कि मैं इस पैटर्न (छोटे 'पी') का उपयोग बहुत अधिक करता हूं। असल में मुझे लगता है कि मेरे इंटरफ़ेस के लिए यह सुरक्षित है कि उनके पास सार्वजनिक होने के लिए संरक्षित dtors हैं। हालांकि मुझे नहीं लगता कि यह वास्तव में एक मुहावरे है (यह उस बारे में बात नहीं करता है) और मुझे लगता है कि जब जीसीसी में चेतावनी जोड़ा गया था तो पुराने 'dtor को आश्वस्त करने के लिए उचित था' वर्चुअल फ़ंक्शन 'नियम है। व्यक्तिगत रूप से मैंने अपडेट किया है कि 'dtor को वर्चुअल फ़ंक्शन होना चाहिए और यदि उपयोगकर्ता इंटरफ़ेस के माध्यम से इंटरफ़ेस के उदाहरणों को मिटाने में सक्षम होना चाहते हैं तो अन्यथा इंटरफ़ेस के माध्यम से इंटरफ़ेस के माध्यम से इंटरफ़ेस के उदाहरणों को हटाने में सक्षम होना चाहिए;

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