2011-12-27 6 views
7

क्या वर्चुअल फ़ंक्शन के लिए परिभाषा आवश्यक है?क्या वर्चुअल फ़ंक्शन अनिवार्य रूप से परिभाषा है?

पर विचार करें नीचे इस नमूने कार्यक्रम:

#include <iostream> 

using namespace std; 

class base 
{ 
    public: 
     void virtual virtualfunc(); 
}; 

class derived : public base 
{ 
    public: 
    void virtualfunc() 
    { 
     cout << "vf in derived class\n"; 
    } 
}; 

int main() 
{ 
    derived d; 
    return 0; 
} 

यह लिंक-त्रुटि देता है:

In function base::base() :: undefined reference to vtable for base

मैं आधार वर्ग में आभासी समारोह के लिए परिभाषा नहीं है। यह त्रुटि क्यों हो रही है भले ही मैंने वर्चुअल फ़ंक्शन को स्पष्ट रूप से लागू नहीं किया है?

दिलचस्प बात जो मुझे मिलती है वह यह है कि यदि मैं कक्षा derived की किसी ऑब्जेक्ट को तुरंत चालू नहीं करता हूं, तो लिंक त्रुटि अब नहीं है। ऐसा क्यों है? उपरोक्त लिंक त्रुटि के साथ तत्काल क्या किया गया है?

+1

अपना संपादन पुन: यदि आप 'व्युत्पन्न' या 'आधार' को तत्काल नहीं करते हैं, तो लिंकर को उन दो वर्गों से किसी भी विधि के साथ कुछ भी क्यों करना होगा? यदि कक्षाओं का संदर्भ नहीं दिया जाता है, तो लिंकर के पास ऑब्जेक्ट फ़ाइलों में उन्हें देखने की कोशिश करने का कोई कारण नहीं है। (जब तक आप एक पुस्तकालय नहीं बना रहे हैं।) – Mat

+0

@Mat: मैं सहमत हूं :) –

उत्तर

10

आईएसओ सी ++ स्टैंडर्ड निर्दिष्ट करता है कि कि शुद्ध आभासी नहीं हैं एक वर्ग के सभी आभासी तरीकों परिभाषित किया जाना चाहिए।

संदर्भ:

सी ++ 03 मानक: 10.3 आभासी कार्यों [class.virtual]

A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required (3.2).

तो या तो आप समारोह शुद्ध आभासी बनाने या उसके लिए कोई परिभाषा प्रदान करना चाहिए।

यदि आप जीसीसी का उपयोग कर रहे हैं, तो आप कुछ मानक त्रुटियों को प्राप्त कर सकते हैं यदि आप इस मानक विनिर्देश का पालन करने में विफल रहते हैं। gcc faq doccuments यह रूप में अच्छी तरह:

The ISO C++ Standard specifies that all virtual methods of a class that are not pure-virtual must be defined, but does not require any diagnostic for violations of this rule [class.virtual]/8 . Based on this assumption, GCC will only emit the implicitly defined constructors, the assignment operator, the destructor and the virtual table of a class in the translation unit that defines its first such non-inline method.

Therefore, if you fail to define this particular method, the linker may complain about the lack of definitions for apparently unrelated symbols. Unfortunately, in order to improve this error message, it might be necessary to change the linker, and this can't always be done.

The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7 .

+0

ग्रेट! उत्कृष्ट :) –

3

आपको या तो एक परिभाषा प्रदान करने की आवश्यकता है, या इसे सार/शुद्ध-विषाणु के रूप में चिह्नित करें।

void virtual virtualfunc() = 0; 
+0

संक्षिप्त और बहुत कुछ यह सब कहता है। – Gravity

8

आप (अपने डिफ़ॉल्ट व्यवहार के साथ) एक आभासी समारोह के एक कार्यान्वयन प्रदान करने के लिए जब तक आप समारोह को परिभाषित "शुद्ध आभासी" होने की जरूरत है।

तो अपने उदाहरण हो सकता है:

class base 
{ 
    public: 
     void virtual virtualfunc() {} //intentionally do nothing; 
}; 

या

class base 
{ 
    public: 
     void virtual virtualfunc()=0; //pure virtual; 
}; 
0

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

वाक्य रचना उन परिभाषित करने के लिए इस प्रकार है:

void virtual virtualfunc() = 0; 
1

vtable के बारे में त्रुटि के जवाब में: इस मामले में आभासी आदेश C++ बताता आधार वर्ग में तरीकों में से एक आभासी तालिका का निर्माण करने के। इस तरह जब आप बहुरूपता का उपयोग करते हैं, तो सी ++ बेस क्लास वर्चुअल विधियों को व्युत्पन्न कक्षा से विधियों के साथ रन टाइम के दौरान समान नाम से प्रतिस्थापित करने में सक्षम है। यह त्रुटि उपयोगकर्ता को बता रही है कि यह प्रतिस्थापन संभव नहीं है। इस त्रुटि को ठीक करने के लिए, आपको या तो परिभाषा के अंत में विधि को लागू करने या "= 0" जोड़कर शुद्ध वर्चुअल के रूप में सेट करने की आवश्यकता होगी।

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

+1

यह गहरा कारण है !! – selfboot

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