2012-04-05 33 views
14

मैं एक आधार वर्ग मीडिया और कई व्युत्पन्न वर्ग, अर्थात् डीवीडी, पुस्तक, आदि ... है आधार वर्ग भी लिखा गया है:सी ++ "आभासी कार्यों, लेकिन कोई आभासी विनाशकर्ता"

class Media{ 
    private: 
     int id; 
     string title; 
     int year; 
    public: 
     Media(){ id = year = 0; title = ""; } 
     Media(int _id, string _title, int _year): id(_id), title(_title), year(_year) {} 
//  virtual ~Media() = 0; 
     void changeID(int newID){ id = newID; } 
     virtual void print(ostream &out); 
}; 

बात है : विनाशक के बिना, जीसीसी मुझे चेतावनी का एक गुच्छा देता है "कक्षा में वर्चुअल फ़ंक्शन हैं लेकिन गैर-वर्चुअल विनाशक" है, लेकिन अभी भी संकलित है और मेरा प्रोग्राम ठीक काम करता है। अब मैं उन कष्टप्रद चेतावनी से छुटकारा पाने के तो मैं एक आभासी नाशक जोड़कर संकलक को संतुष्ट करना चाहते हैं, परिणाम है: यह त्रुटि के साथ, संकलन नहीं करता है:

undefined reference to Media::~Media()

नाशक शुद्ध आभासी बनाना नहीं है समस्या का समाधान। तो क्या गलत हो गया है?

+1

आप पहली जगह में शुद्ध आभासी कन्स्ट्रक्टर क्यों चाहते हैं? एक खाली आभासी कन्स्ट्रक्टर बस अच्छी तरह से काम करता है (और यह गैर व्हाइटस्पेस वर्णों की संख्या के बराबर है) – hirschhornsalz

+1

@ लचियनग्रिगोर मेरा मतलब यह नहीं था। मैं इसे आपके लिए दोहराता हूं: आप कक्षा मीडिया को सार क्यों बनाना चाहते हैं? – hirschhornsalz

+1

@drhirsch आमतौर पर क्योंकि आप इसकी रचना को अस्वीकार करना चाहते हैं। शायद मीडिया प्रकार का एक वस्तु समझ में नहीं आता है। –

उत्तर

15

तुम भी आभासी नाशक परिभाषित करने की जरूरत, न केवल जोड़ें।

//Media.h 
class Media{ 
    //.... 
    virtual ~Media() = 0; 
}; 

//Media.cpp 
#include "Media.h" 
//.... 
Media::~Media() {}; 

कारण आप चेतावनी प्राप्त है कि सभी वर्गों कि से प्राप्त हो जाएगा एक आभासी या संरक्षित (क्रेडिट @Steve) नाशक होनी चाहिए, अन्यथा अपरिभाषित व्यवहार में आधार वर्ग परिणाम के लिए एक सूचक के माध्यम से एक उदाहरण को हटाने ।

नोट आपको विनाशकों के लिए परिभाषा प्रदान करना है, भले ही वे शुद्ध वर्चुअल हों।

+2

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

+0

@SteveJessop दाएं, संपादित। धन्यवाद! –

+0

विश्वास नहीं कर सकता मुझे एक खाली विनाशक को लागू करना है। समस्या हल हो गई, धन्यवाद दोस्तों! –

6

आप आभासी नाशक को लागू करना चाहिए, यह शुद्ध आभासी नहीं बनाते हैं।

अधिक जानकारी के लिए this समान प्रश्न (आभासी विनाशक त्रुटि के दृष्टिकोण से, चेतावनी नहीं) को देखें।

संपादित करें: अधिक सामान्य समाधान, LuchianGrigore की टिप्पणी के जवाब में (आप इसे ओर इशारा करते हुए के लिए धन्यवाद)

तुम भी नाशक शुद्ध आभासी बनाने के लिए और के रूप में यह ऊपर उल्लेख किया है प्रश्न में बताया है लागू कर सकते हैं।

कक्षाओं में वर्चुअल विनाशकों का उपयोग बेस क्लास के तत्कालता को रोकने के लिए होना चाहिए (यानी जब आपके पास वर्ग सार बनाने के लिए कोई अन्य शुद्ध वर्चुअल विधियां नहीं हैं)।

+1

शुद्ध वर्चुअल विनाशकों का अपना उद्देश्य है। लेकिन अगर शुद्ध घोषित किया गया है, तो भी एक परिभाषा की आवश्यकता है। –

+0

हां, मेरा जवाब केवल त्रुटि के बारे में था। मैं एक वर्ग में शुद्ध वर्चुअल विनाशकों का उपयोग और मेरे जवाब में उन्हें लागू करने का एक तरीका जोड़ूंगा। +1 –

3

आपने जो टिप्पणी की है वह एक विनाशक के लिए शुद्ध-आभासी घोषणा है। इसका मतलब है कि उस वर्ग के किसी ऑब्जेक्ट को तुरंत चालू करने में सक्षम होने के लिए फ़ंक्शन को व्युत्पन्न कक्षा में ओवरराइड किया जाना चाहिए।

virtual ~Media() {} 
0

टिप्पणी हटाएं घोषणा पहले और उसके बाद कोशिश वर्ग घोषणा

Media::~Media(){} 
+1

नहीं। कक्षा घोषणा के बाद इसे जोड़ने से जुड़ाव के दौरान कई परिभाषाएं मिलेंगी। परिभाषा केवल एक अनुवाद इकाई में होनी चाहिए। –

+0

धन्यवाद लूचियन, मैंने अभी अपना जवाब संपादित किया – Hiren

+1

यह अभी भी सही नहीं है। कक्षा घोषणा के बाद इसे जोड़ना, हेडर फ़ाइल के अंदर, परिणामस्वरूप त्रुटि होगी। –

5

The thing is: without the destructor, GCC gives me a bunch of warnings "class has virtual functions but non-virtual destructor", but still compiles and my program works fine

इस के बाद निम्न पंक्ति जोड़कर:

क्या आप चाहते हैं सिर्फ एक आभासी समारोह के रूप में नाशक की एक परिभाषा है आधुनिक सी ++ में एक कष्टप्रद चेतावनी है, लेकिन पुराने ऑब्जेक्ट-शैली सी ++ में यह आमतौर पर सही है।

समस्या तरीका है अपनी वस्तुओं विलुप्त कर रहे हैं के बारे में है।एक साधारण परीक्षण:

#include <iostream> 

class Base {}; 
class Derived: public Base { public: ~Derived() { std::cout << "Aargh\n"; } }; 

int main() { 
    Base* b = new Derived(); 
    Derived* d = new Derived(); 

    delete d; 
    delete b; 
} 

यह प्रिंट:

Aargh 

हां, केवल एक बार।

समस्या यह है कि जब आप को Base* प्रकार के चर पर कॉल करते हैं, तो Base::~Base() विधि कहा जाता है। यदि यह virtual है, तो कॉल को गतिशील रूप से अंतिम विधि (गतिशील प्रकार के आधार पर) भेजा जाता है, इस मामले में Derived::~Derived(), लेकिन यदि ऐसा नहीं है, तो Derived::~Derived() कभी नहीं कहा जाता है, इस प्रकार कभी निष्पादित नहीं किया जाता है।

इसलिए, यदि आप आधार प्रकारों पर delete (या स्मार्ट पॉइंटर्स जो इसे आपके लिए करते हैं) पर कॉल करना चाहते हैं, तो आपको अपनी कक्षा परिभाषाओं में virtual ~Base() {} जोड़ने की आवश्यकता है। यही कारण है कि जब आप virtual विनाशक के बिना एक पॉलिमॉर्फिक कक्षा बनाते हैं तो जीसीसी आपको चेतावनी देता है।


नोट: समय बदल गया है, और उसके बाद से मैं बजना में -Wdelete-non-virtual-dtor लागू किया है और यह जीसीसी में रूप में अच्छी तरह से दोहराया गया था।

-Wnon-virtual-dtor लाइब्रेरी लेखकों के लिए उपयोगी है (जैसा कि यह आधार वर्ग पर चेतावनी देता है), लेकिन अधिक झूठी सकारात्मक दर हो सकती है; दूसरी तरफ -Wdelete-non-virtual-dtor कॉल साइट पर आग लगती है, और इसमें बहुत कम झूठी सकारात्मक दरें होती हैं (जो कक्षा के "पॉलिमॉर्फिक" संपत्ति को हटाने के लिए आम तौर पर final मिर्च करके काम कर सकती हैं)।

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