C ++ में निजी वर्चुअल विधि


125

C ++ में एक निजी विधि को आभासी बनाने से क्या फायदा है?

मैंने इसे एक ओपन सोर्स C ++ प्रोजेक्ट में देखा है:

class HTMLDocument : public Document, public CachedResourceClient {
private:
    virtual bool childAllowed(Node*);
    virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};

9
मुझे लगता है कि सवाल पीछे की तरफ है। कुछ को आभासी बनाने का कारण हमेशा समान होता है: व्युत्पन्न वर्गों को इसे ओवरराइड करने की अनुमति देना। तो सवाल यह होना चाहिए: एक आभासी विधि को निजी बनाने से क्या फायदा है? जिसका उत्तर है: डिफ़ॉल्ट रूप से सब कुछ निजी बनाएं। :-)
श्रीवत्सआर

1
@ श्रीवत्सआर लेकिन आपने स्वयं के प्रश्न का उत्तर नहीं दिया ......
स्पेन्सर

@ श्रीवत्सआर मुझे लगा कि आप एक अलग तरीके से पीछे की ओर इशारा करते हैं: वर्चुअल विधि को निजी नहीं बनाने का क्या फायदा है ?
पीटर - मोनिका

जवाबों:


116

हर्ब सटर ने यहाँ बहुत बारीकी से समझाया है

दिशानिर्देश # 2: आभासी कार्यों को निजी बनाना पसंद करते हैं।

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


जैसा कि आप मेरे उत्तर से अनुमान लगा सकते हैं, मुझे लगता है कि सटर की गाइडलाइन # 3 बल्कि गाइडलाइन # 2 को खिड़की से बाहर निकालती है।
स्पेंसर

66

यदि विधि आभासी है, तो यह व्युत्पन्न वर्गों द्वारा ओवरराइड किया जा सकता है, भले ही यह निजी हो। जब वर्चुअल विधि को कॉल किया जाता है, तो ओवरराइड किए गए संस्करण को लागू किया जाएगा।

(प्रसून सौरव द्वारा अपने जवाब में उद्धृत हर्ब सटर के विरोध में, सी ++ एफएक्यू लाइट निजी आभासी लोगों के खिलाफ सिफारिश करता है , ज्यादातर क्योंकि यह अक्सर लोगों को भ्रमित करता है।)


41
ऐसा प्रतीत होता है कि C ++ FAQ Lite ने अपनी सिफारिश बदल दी है: " C ++ FAQ को निजी वर्चुअल के बजाय संरक्षित वर्चुअल का उपयोग करके पूर्व में अनुशंसित किया गया है। हालांकि, निजी वर्चुअल दृष्टिकोण अब काफी आम है कि नौसिखियों का भ्रम एक चिंता से कम नहीं है। "
Zack मानव

19
हालांकि, विशेषज्ञों का भ्रम एक चिंता का विषय है। मेरे बगल में बैठे चार C ++ पेशेवरों में से कोई भी निजी वर्चुअल के बारे में नहीं जानता था।
न्यूटनएक्स

12

आभासी सदस्य को निजी घोषित करने के लिए सभी कॉल करने के बावजूद, तर्क बस पानी नहीं रखता है। अक्सर, एक वर्चुअल फ़ंक्शन के एक व्युत्पन्न वर्ग के ओवरराइड को बेस क्लास संस्करण को कॉल करना होगा। यह घोषित नहीं किया जा सकता है private:

class Base
{
 private:

 int m_data;

 virtual void cleanup() { /*do something*/ }

 protected:
 Base(int idata): m_data (idata) {}

 public:

 int data() const { return m_data; }
 void set_data (int ndata) { m_data = ndata; cleanup(); }
};

class Derived: public Base
{
 private:
 void cleanup() override
 {
  // do other stuff
  Base::cleanup(); // nope, can't do it
 }
 public:
 Derived (int idata): base(idata) {}
};

आप है आधार वर्ग प्रणाली की घोषणा करने के लिए protected

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

class Base
{
 ...
 protected:
 // chained virtual function!
 // call in your derived version but nowhere else.
 // Use set_data instead
 virtual void cleanup() { /* do something */ }
 ...

इस प्रकार हर्ब सटर की गाइडलाइन # 3 ... लेकिन घोड़ा वैसे भी खलिहान से बाहर है।

जब आप कुछ घोषित करते हैं, protectedतो आप किसी भी व्युत्पन्न वर्ग के लेखक पर भरोसा करने के लिए संरक्षित आंतरिकों को समझने और ठीक से उपयोग करने के लिए, जिस तरह से एक friendघोषणा privateसदस्यों के लिए एक गहरा विश्वास का अर्थ है ।

जिन उपयोगकर्ताओं को उस ट्रस्ट का उल्लंघन करने से बुरा व्यवहार मिलता है (जैसे कि आपके दस्तावेज़ पढ़ने के लिए परेशान न होकर 'क्लूलेस' लेबल) केवल स्वयं को दोषी मानते हैं।

अपडेट : मेरे पास कुछ प्रतिक्रियाएं हैं जो दावा करती हैं कि आप निजी वर्चुअल फ़ंक्शंस का उपयोग करके इस तरह से वर्चुअल फ़ंक्शन कार्यान्वयन "चेन" कर सकते हैं। यदि हां, तो मुझे यकीन है कि यह देखना पसंद करेंगे।

C ++ संकलक मैं निश्चित रूप से एक व्युत्पन्न वर्ग कार्यान्वयन को एक निजी बेस क्लास कार्यान्वयन कॉल नहीं होने दूंगा।

यदि C ++ समिति ने "निजी" को इस विशिष्ट पहुंच की अनुमति देने के लिए आराम किया है, तो मैं सभी निजी आभासी कार्यों के लिए हूं। जैसा कि यह खड़ा है, घोड़े चोरी होने के बाद भी हमें खलिहान का दरवाजा बंद करने की सलाह दी जा रही है।


3
मुझे आपका तर्क अमान्य लगता है। आपको एपीआई के एक डेवलपर के रूप में एक ऐसे इंटरफ़ेस के लिए प्रयास करना चाहिए जो गलत तरीके से उपयोग करना कठिन है और ऐसा करने में अपनी गलतियों के लिए किसी अन्य डेवलपर को स्थापित नहीं करना है। आप अपने उदाहरण में क्या करना चाहते हैं, केवल निजी आभासी तरीकों से लागू किया जा सकता है।
सिगी

1
ऐसा मैं नहीं कह रहा था। लेकिन आप एक निजी बेस क्लास फ़ंक्शन को कॉल करने की आवश्यकता के बिना उसी प्रभाव को प्राप्त करने के लिए अपने कोड का पुनर्गठन कर सकते हैं
sigy

3
अपने उदाहरण में आप के व्यवहार का विस्तार करना चाहते हैं set_data। निर्देश m_data = ndata;और cleanup();इस प्रकार एक अपरिवर्तनीय माना जा सकता है जो सभी कार्यान्वयनों के लिए होना चाहिए। इसलिए cleanup()गैर-आभासी और निजी बनाएं । एक अन्य निजी पद्धति में कॉल जोड़ें जो आभासी हो और आपकी कक्षा का विस्तार बिंदु हो। अब आपके व्युत्पन्न वर्गों के लिए आधार को कॉल करने की कोई आवश्यकता cleanup()नहीं है, आपका कोड साफ रहता है और आपके इंटरफ़ेस का गलत तरीके से उपयोग करना कठिन है।
सिगी

2
@sigy जो सिर्फ गोलपोस्ट को हिलाता है। आपको आपराधिक उदाहरण से परे देखने की जरूरत है। जब आगे वंशज होते हैं cleanup()जिन्हें श्रृंखला में सभी को कॉल करने की आवश्यकता होती है, तो तर्क अलग हो जाता है। या आप श्रृंखला में प्रत्येक वंश के लिए एक अतिरिक्त आभासी कार्य की सिफारिश कर रहे हैं? Ick। यहां तक ​​कि हर्ब सटर ने अपने दिशानिर्देश # 3 में एक बचाव के रूप में संरक्षित आभासी कार्यों की अनुमति दी। वैसे भी, कुछ वास्तविक कोड के बिना आप मुझे कभी नहीं मनाएंगे।
स्पेंसर

2
तो फिर असहमत होने के लिए सहमत हो;)
sigy

9

स्कॉट मैयर्स के 'प्रभावी सी ++', आइटम 35 को पढ़ते हुए मैं पहली बार इस अवधारणा पर आया था : वर्चुअल फ़ंक्शंस के विकल्पों पर विचार करें। मैं स्कॉट मेयर्स को दूसरों के लिए संदर्भित करना चाहता था जो रुचि हो सकती है।

यह गैर-वर्चुअल इंटरफ़ेस मुहावरे के माध्यम से टेम्पलेट विधि पैटर्न का हिस्सा है : सार्वजनिक सामना करने वाले तरीके आभासी नहीं हैं; बल्कि, वे वर्चुअल मेथड कॉल को लपेटते हैं जो निजी हैं। निजी वर्चुअल फंक्शन कॉल से पहले और बाद में बेस क्लास लॉजिक चला सकता है:

public:
  void NonVirtualCalc(...)
  {
    // Setup
    PrivateVirtualCalcCall(...);
    // Clean up
  }

मुझे लगता है कि यह एक बहुत ही दिलचस्प डिजाइन पैटर्न है और मुझे यकीन है कि आप देख सकते हैं कि अतिरिक्त नियंत्रण कैसे उपयोगी है।

  • आभासी कार्य क्यों करें private? सबसे अच्छा कारण यह है कि हमने पहले से ही एक publicसामना करने का तरीका प्रदान किया है ।
  • बस इसे क्यों नहीं बनाया protectedजाए ताकि मैं अन्य दिलचस्प चीजों के लिए विधि का उपयोग कर सकूं? मुझे लगता है कि यह हमेशा आपके डिजाइन पर निर्भर करेगा और आप कैसे विश्वास करते हैं कि बेस क्लास फिट बैठता है। मेरा तर्क है कि व्युत्पन्न वर्ग निर्माता को आवश्यक तर्क को लागू करने पर ध्यान देना चाहिए; बाकी सब कुछ पहले से ही ध्यान रखा जाता है। इसके अलावा, एनकैप्सुलेशन की बात है।

C ++ के दृष्टिकोण से, यह पूरी तरह से एक निजी आभासी विधि को ओवरराइड करने के लिए वैध है, भले ही आप इसे अपनी कक्षा से कॉल करने में सक्षम न हों। यह ऊपर वर्णित डिज़ाइन का समर्थन करता है।


3

मैं उन्हें बेस क्लास के लिए व्युत्पन्न वर्गों को "रिक्त स्थान को भरने" के लिए अनुमति देता हूं ताकि उपयोगकर्ताओं को अंत करने के लिए इस तरह के छेद को उजागर किए बिना एक आधार वर्ग के लिए। उदाहरण के लिए, मेरे पास एक सामान्य आधार से प्राप्त होने वाली अत्यधिक स्टेटफुल ऑब्जेक्ट हैं, जो केवल समग्र राज्य मशीन के 2/3 को लागू कर सकते हैं (व्युत्पन्न कक्षाएं टेम्पलेट तर्क के आधार पर शेष 1/3 प्रदान करती हैं, और आधार एक टेम्पलेट नहीं हो सकता है अन्य कारणों से)।

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

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.