2009-07-01 28 views
17

मैं अभी कक्षा में सी ++ के बारे में सीख रहा हूं और मुझे शुद्ध वर्चुअल फ़ंक्शंस नहीं है। मैं समझता हूं कि बाद में उन्हें व्युत्पन्न कक्षा में उल्लिखित किया गया है, लेकिन आप इसे 0 के बराबर क्यों घोषित करना चाहते हैं यदि आप इसे व्युत्पन्न कक्षा में परिभाषित करने जा रहे हैं?सी ++ में शुद्ध आभासी कार्यों के उपयोग क्या हैं?

+2

आपके लिए और कुछ जिन्होंने आपको वोट दिया: पाठ्यपुस्तक ने WHY को समझाया नहीं; और चूंकि मुझे यकीन है कि कोई और Google इसे करेगा, मैंने इसे यहां पूछा। इस तरह कोई और लाभ उठा सकता है। – patricksweeney

+0

तब वह पाठ्यपुस्तक क्या थी? स्पष्ट रूप से, यहां जवाब (जैसा कि सामान्य प्रश्नों के लिए सामान्य है) न तो विशेष रूप से अच्छे और न ही सटीक हैं। तो ऐसा नहीं लगता कि आप इस तरह के प्रश्न पूछकर एक सेवा कर रहे हैं। –

+0

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

उत्तर

30

संक्षेप में, यह कक्षा सार बनाना है, ताकि इसे तुरंत चालू नहीं किया जा सके, लेकिन एक बाल वर्ग शुद्ध वर्चुअल विधियों को एक ठोस वर्ग बनाने के लिए ओवरराइड कर सकता है। यह C++ में एक इंटरफ़ेस को परिभाषित करने का एक अच्छा तरीका है।

+1

मैं बदलने की सिफारिश करता हूं: "... एक बाल वर्ग ..." ... "एक पत्ता वर्ग चाहिए ..."। –

+0

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

+1

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

12

यह फ़ंक्शन को परिभाषित करने के लिए व्युत्पन्न कक्षा को मजबूर करता है।

0

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

जब आप सी ++ में कोई विधि का आह्वान करते हैं, तो संकलक को यह सुनिश्चित करने की आवश्यकता होती है कि विधि उस ऑब्जेक्ट पर समर्थित होगी।

शुद्ध वर्चुअल फ़ंक्शन घोषित करके, आप "प्लेसहोल्डर" डाल रहे हैं कि संकलक कहने के लिए उपयोग कर सकता है "ओह ... मुझे पता है कि जो भी इस चर द्वारा संदर्भित किया जा रहा है वह उस कॉल को स्वीकार करेगा" क्योंकि वास्तविक ठोस प्रकार इसे लागू करेंगे। हालांकि, आपको अमूर्त प्रकार में कार्यान्वयन प्रदान करने की आवश्यकता नहीं है।

यदि आपने कुछ भी घोषित नहीं किया है, तो संकलक के पास यह गारंटी देने का कोई प्रभावी तरीका नहीं होगा कि यह सभी उपप्रकारों द्वारा लागू किया जाएगा।

बेशक, यदि आप पूछ रहे हैं कि आप कक्षा सार क्यों बनाना चाहते हैं, तो उस पर बहुत सारी जानकारी है।

4

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

+1

सही, अधिक सटीक: "सभी विरासतकर्ताओं को मजबूर करने का एक तरीका परिभाषित हस्ताक्षर का पालन करता है" –

3

स्टीवन Sudit के जवाब देने के लिए जोड़ने के लिए:

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

इसका एक उदाहरण होगा यदि आपके पास बेस क्लास (शायद आकार) था जिसका उपयोग आप अपने सदस्य वर्गों के कई सदस्य कार्यों को परिभाषित करने के लिए करते हैं, लेकिन आकार घोषित करने और उपयोगकर्ताओं को मजबूर करने के उदाहरण को रोकना चाहते हैं

गैर सार वर्गों ऊपर जेफ के जवाब आभासी सदस्य कार्य शामिल कर सकते हैं और instantiated जा: केवल व्युत्पन्न वर्ग (जो हो, आयत, त्रिभुज, पेंटागन, और इतने पर कर सकते हैं)

RE उपयोग करने के लिए। असल में, सदस्य कार्यों को ओवरलोड करने के लिए यह आवश्यक है क्योंकि डिफ़ॉल्ट C++ किसी चर के रनटाइम प्रकार को निर्धारित नहीं करता है, लेकिन जब वर्चुअल कीवर्ड का उपयोग करके परिभाषित किया जाता है, तो यह होगा।

इस कोड पर विचार करें (ध्यान दें, accessors, mutators, कंस्ट्रक्टर्स, आदि स्पष्टता के लिए शामिल नहीं हैं):

class Person{ 
    int age; 

    public: 
    virtual void print(){ 
     cout << age <<endl; 
    } 
} 

class Student: public Person{ 
    int studentID 

    public: 
    void print(){ 
     cout << age << studentID <<endl; 
    } 
} 

अब जब इस कोड चलाने:

Person p = new Student(); 
p.print(); 

आभासी बिना कीवर्ड, केवल उम्र मुद्रित की जाएगी, उम्र और छात्र आईडी छात्र वर्ग

(यह उदाहरण सी ++ से बहुत समान पर आधारित है) आर जावा प्रोग्रामर http://www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X)

@ स्टीवन सुडिट: आप पूरी तरह से सही हैं, मैंने वास्तविक विरासत को शामिल करने के लिए उपेक्षित किया, दोह! एक्सेसर्स इत्यादि चीजों को स्पष्ट रखने के लिए शामिल नहीं हैं, और अब मैंने इसे और अधिक स्पष्ट बना दिया है। 3-7-09: सभी निश्चित

+0

मेरा मानना ​​है कि आपका उदाहरण टूटा हुआ है, क्योंकि इसमें विरासत शामिल नहीं है, और निजी डेटा सदस्यों के मूल्यों को कभी भी सेट करने का कोई तरीका नहीं है । इसके पीछे विचार बिल्कुल सही है। –

+0

यह बेहतर है, लेकिन अभी भी सही नहीं है: बाल वर्ग के पास अपना आयु डेटा सदस्य नहीं होना चाहिए। –

+0

इसके अलावा, नीचे की तात्कालिकता कन्स्ट्रक्टर के चारों ओर कोष्ठक की कमी है। –

7

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

एक अमूर्त वर्ग का एक उदाहरण:

class Foo { 

    // pure virtual, must be implemented by subclasses 
    virtual public void myMethod() = 0; 

    // normal method, will be available to all subclasses, 
    // but *can* be overridden 
    virtual public void myOtherMethod(); 
}; 

एक वर्ग है जिसमें हर विधि सार एक अंतरफलक के रूप में इस्तेमाल किया जा सकता है, उसमें शामिल सभी तरीकों को लागू करने से इंटरफेस के अनुरूप सभी उपवर्गों की जरूरत पड़ेगी।

एक इंटरफेस का एक उदाहरण:

class Bar { 

    // all method are pure virtual; subclasses must implement 
    // all of them 
    virtual public void myMethod() = 0; 

    virtual public void myOtherMethod() = 0; 
}; 
+0

मुझे लगता है कि आपको "शुद्ध * वर्चुअल विधि वाला कोई भी वर्ग" होना चाहिए। – Dan

+0

मैं शायद यह जोड़ दूंगा कि एक सार बेस क्लास में न केवल विधियों के कार्यान्वयन हो सकते हैं, लेकिन डेटा सदस्यों के साथ ही। एक इंटरफ़ेस न तो होना चाहिए। सी ++ में, यह सिर्फ एक सम्मेलन है। सी # या जावा में, यह एक नियम है। –

3

कल्पना कीजिए मैं आकार के कई प्रकार मॉडल बनाना चाहते हैं, और सभी एक अच्छी तरह से परिभाषित क्षेत्र है। मैं तय है कि हर आकार के वारिस चाहिए IShape (इंटरफेस के लिए "मैं"), और IShape एक GetArea() विधि में शामिल होंगे: अगर है कि आकार नहीं है मैं एक आकार के क्षेत्र गणना कैसे करना चाहिए:

class IShape { 
    virtual int GetArea(); 
}; 

अब समस्या GetArea() ओवरराइड करें? यही है, सबसे अच्छा डिफ़ॉल्ट कार्यान्वयन क्या है? मंडल पीआई * त्रिज्या^2 का उपयोग करते हैं, वर्ग लंबाई लंबाई 2, समांतरोग्राम और आयताकार आधार * ऊंचाई का उपयोग करते हैं, त्रिकोण 1/2 आधार * ऊंचाई, rhombuses, pentagons, octagons, आदि का उपयोग अन्य सूत्रों का उपयोग करें।

तो मैं कहते हैं कि "यदि आप एक आकार रहे हैं आप क्षेत्रफल की गणना करने के लिए एक रास्ता को परिभाषित करना होगा, लेकिन शापित अगर मुझे पता है कि कि हो जाएगा" विधि शुद्ध आभासी को परिभाषित करते हुए:

class IShape { 
    virtual int GetArea() = 0; 
}; 
+0

नहीं मिलेगा एरिया को दोनों मामलों में आभासी घोषित किया जाना है? –

+0

इसे बेस क्लास में आभासी घोषित करने की आवश्यकता है। सुधारों के लिए धन्यवाद। –

1

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

उदाहरण के लिए:

class IStudent 
{ 
    public: 
    virtual ~IStudent(){}; 
    virtual std::string getName() = 0; 
}; 


class Student : public IStudent 
{ 
    public: 
    std::string name; 
    std::string getName() { return name; }; 
    void setName(std::string in) { name = in; }; 
}; 

class School 
{ 
    public: 
    void sendStudentToDetention(IStudent *in) { 
     cout << "The student sent to detention is: "; 
     cout << in->getName() << endl; 
    }; 
}; 

int main() 
{ 
    Student student; 
    student.setName("Dave"); 

    School school; 
    school.sendStudentToDetention(&student); 
return 0; 
} 

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

+0

मैं सुझाव दूंगा कि छात्र में "नाम" डेटा सदस्य निजी होना चाहिए, या कम से कम संरक्षित होना चाहिए। मैं संदर्भ में छात्र द्वारा संदर्भित करने की भी सिफारिश करता हूं, पॉइंटर नहीं। अंत में, एक असली दुनिया छात्र वर्ग शायद अपने कन्स्ट्रक्टर में नाम ले जाएगा। –

+0

मैं उन सभी के साथ सहमत हूं। जब मैं इस उदाहरण को वास्तविक तेज़ी से टाइप करता था तो वे सिर्फ निरीक्षण थे। – davidivins

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