आपको C ++ में 'मित्र' का उपयोग कब करना चाहिए?


354

मैं C ++ FAQ के माध्यम से पढ़ रहा हूं और friendघोषणा के बारे में उत्सुक था । मैंने व्यक्तिगत रूप से इसका इस्तेमाल कभी नहीं किया है, हालांकि मुझे भाषा की खोज करने में दिलचस्पी है।

उपयोग करने का एक अच्छा उदाहरण क्या है friend ?


एफएक्यू को थोड़ी देर पढ़ना मुझे << >>ऑपरेटर के ओवरलोडिंग और उन वर्गों के दोस्त के रूप में जोड़ने के विचार को पसंद है । हालांकि मुझे यकीन नहीं है कि यह एनकैप्सुलेशन को कैसे नहीं तोड़ता है। ये अपवाद OOP की सख्ती के भीतर कब रह सकते हैं?


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

1
आप एक मित्र वर्ग का उपयोग करेंगे जहां पहले से ही तंग युग्मन है। इसे ही बनाया गया है। उदाहरण के लिए, एक डेटाबेस तालिका और उसके सूचकांक को कसकर युग्मित किया जाता है। जब कोई तालिका बदलती है, तो उसके सभी अनुक्रमों को अद्यतन किया जाना चाहिए। इसलिए, क्लास DBIndex DBTable को एक मित्र घोषित करेगा ताकि DBTable इंडेक्स इंटर्ल्स को सीधे एक्सेस कर सके। लेकिन DBIndex के लिए कोई सार्वजनिक इंटरफ़ेस नहीं होगा; यह भी एक सूचकांक पढ़ने के लिए समझ में नहीं आता है।
shawnhcorey 12

थोड़ा व्यावहारिक अनुभव के साथ OOP "शुद्धतावादियों" का तर्क है कि दोस्त OOP सिद्धांतों का उल्लंघन करता है, क्योंकि एक वर्ग को अपने निजी राज्य का एकमात्र अनुचर होना चाहिए। यह ठीक है, जब तक आप एक सामान्य स्थिति का सामना नहीं करते हैं जहां दो वर्गों को साझा निजी राज्य बनाए रखने की आवश्यकता होती है।
कालस 15

जवाबों:


335

सबसे पहले (IMO) कहने वाले लोगों की बात नहीं मानते friend कि यह उपयोगी नहीं है। यह उपयोगी है। कई स्थितियों में आपके पास डेटा या कार्यक्षमता वाले ऑब्जेक्ट होंगे जो सार्वजनिक रूप से उपलब्ध होने का इरादा नहीं रखते हैं। यह कई लेखकों के साथ बड़े कोडबेस का विशेष रूप से सच है जो केवल विभिन्न क्षेत्रों से सतही रूप से परिचित हो सकते हैं।

मित्र निर्दिष्टकर्ता के लिए विकल्प हैं, लेकिन अक्सर वे बोझिल होते हैं (सीपीपी-स्तरीय कंक्रीट कक्षाएं / नकाबपोश टाइपडिफ्स) या मूर्ख नहीं (टिप्पणियाँ या फ़ंक्शन नाम सम्मेलनों)।

उत्तर पर;

friendविनिर्देशक वर्ग दोस्त वक्तव्य देने के भीतर सुरक्षित डेटा या कार्यक्षमता के लिए नामित वर्ग उपयोग की अनुमति देता। उदाहरण के लिए नीचे दिए गए कोड में कोई भी अपने नाम के लिए एक बच्चे से पूछ सकता है, लेकिन केवल माँ और बच्चा ही नाम बदल सकते हैं।

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

class Child
{
//Mother class members can access the private parts of class Child.
friend class Mother;

public:

  string name( void );

protected:

  void setName( string newName );
};

114
अतिरिक्त नोट के रूप में, C ++ FAQ में उल्लेख है कि friend एनकैप्सुलेशन को बढ़ाता है । सदस्यों को चयनात्मक पहुंचfriend प्रदान करता है , ठीक उसी तरह जैसे । सार्वजनिक पहुंच प्रदान करने की तुलना में कोई भी सुव्यवस्थित नियंत्रण बेहतर है। अन्य भाषाएं चयनात्मक पहुंच तंत्र को भी परिभाषित करती हैं, सी # पर विचार करें । के उपयोग के आस-पास की अधिकांश नकारात्मक आलोचना तंग युग्मन से संबंधित है, जिसे आमतौर पर एक बुरी चीज के रूप में देखा जाता है। हालांकि, कुछ मामलों में, तंग युग्मन ठीक वही है जो आप चाहते हैं और आपको वह शक्ति प्रदान करता है। protectedinternalfriendfriend
एंड्री कैरन

5
क्या आप कृपया (सीपीपी-स्तरीय ठोस वर्गों) और (नकाबपोश टाइप्डेफ़्स), एंड्रयू के बारे में और अधिक बता सकते हैं ?
ओमरऑथमैन

18
यह उत्तर यह समझाने में अधिक केंद्रित है कि friendएक प्रेरक उदाहरण प्रदान करने के बजाय क्या है । विंडो / WindowManager उदाहरण दिखाए गए उदाहरण से बेहतर है, लेकिन बहुत अस्पष्ट है। यह उत्तर प्रश्न के एनकैप्सुलेशन भाग को भी संबोधित नहीं करता है।
bames53

4
इसलिए प्रभावी रूप से 'मित्र' मौजूद है क्योंकि C ++ में पैकेज की कोई धारणा नहीं है जिसमें सभी सदस्य कार्यान्वयन विवरण साझा कर सकें? मैं वास्तव में वास्तविक दुनिया के उदाहरण में दिलचस्पी लूंगा।
वेबर 2

1
@OMGtechy आपको यह नहीं करना होगा कि यदि C ++ में पैकेज की धारणा है, तो यह मेरे पिछले कथन के अनुरूप है। यहां एक उदाहरण है गो में जो निजी सदस्यों तक पहुंचने के लिए दोस्तों के बजाय पैकेज का उपयोग करता है: play.golang.org/p/xnade4GBAL
weberc2

162

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

यह कहने के लिए पर्याप्त है कि मैं आपके डिज़ाइन के आवश्यक घटक के रूप में मित्र कीवर्ड का उपयोग नहीं करूंगा।


ठीक यही मैं इसके लिए उपयोग करता हूं। वह या केवल सदस्य चर को संरक्षित करने के लिए सेट करें। यह सिर्फ एक शर्म की बात है कि यह C ++ / CLI के लिए काम नहीं करता है :-(
जॉन केज

12
व्यक्तिगत रूप से मैं इसे हतोत्साहित करूंगा। आमतौर पर आप एक इंटरफ़ेस का परीक्षण कर रहे हैं, यानी इनपुट का एक सेट आउटपुट (एस) का अपेक्षित सेट देता है। आपको आंतरिक डेटा का निरीक्षण करने की आवश्यकता क्यों है?
ग्रीम

55
@ ग्रेमी: क्योंकि एक अच्छी परीक्षण योजना में सफेद बॉक्स और ब्लैक बॉक्स परीक्षण दोनों शामिल हैं।
बेन वोइग्ट

1
मैं @Gememe से सहमत हूं, जैसा कि इस उत्तर में पूरी तरह से समझाया गया है ।
एलेक्सिस लेक्लर

2
@ ग्रेमी यह सीधे आंतरिक डेटा नहीं हो सकता है। मैं एक ऐसा तरीका हो सकता हूं जो उस डेटा पर एक विशिष्ट ऑपरेशन या कार्य करता है जहां वह विधि कक्षा के लिए निजी है और सार्वजनिक रूप से सुलभ नहीं होनी चाहिए, जबकि किसी अन्य ऑब्जेक्ट को उस वर्ग की संरक्षित विधि को अपने स्वयं के डेटा के साथ फीड या बीज करना पड़ सकता है।
फ्रांसिस कूगलर

93

friendकीवर्ड अच्छा उपयोग करता है की एक संख्या है। यहाँ दो उपयोग मुझे तुरंत दिखाई दे रहे हैं:

मित्र परिभाषा

मित्र परिभाषा किसी कार्य को वर्ग-दायरे में परिभाषित करने की अनुमति देती है, लेकिन फ़ंक्शन को सदस्य फ़ंक्शन के रूप में परिभाषित नहीं किया जाएगा, लेकिन एन्क्लोजिंग नेमस्पेस के एक स्वतंत्र फ़ंक्शन के रूप में, और तर्क आश्रित देखने के लिए सामान्य रूप से दिखाई नहीं देगा। यह ऑपरेटर ओवरलोडिंग के लिए विशेष रूप से उपयोगी बनाता है:

namespace utils {
    class f {
    private:
        typedef int int_type;
        int_type value;

    public:
        // let's assume it doesn't only need .value, but some
        // internal stuff.
        friend f operator+(f const& a, f const& b) {
            // name resolution finds names in class-scope. 
            // int_type is visible here.
            return f(a.value + b.value);
        }

        int getValue() const { return value; }
    };
}

int main() {
    utils::f a, b;
    std::cout << (a + b).getValue(); // valid
}

निजी CRTP बेस क्लास

कभी-कभी, आपको एक नीति की जरूरत होती है जो व्युत्पन्न वर्ग तक पहुंच की आवश्यकता है:

// possible policy used for flexible-class.
template<typename Derived>
struct Policy {
    void doSomething() {
        // casting this to Derived* requires us to see that we are a 
        // base-class of Derived.
        some_type const& t = static_cast<Derived*>(this)->getSomething();
    }
};

// note, derived privately
template<template<typename> class SomePolicy>
struct FlexibleClass : private SomePolicy<FlexibleClass> {
    // we derive privately, so the base-class wouldn't notice that, 
    // (even though it's the base itself!), so we need a friend declaration
    // to make the base a friend of us.
    friend class SomePolicy<FlexibleClass>;

    void doStuff() {
         // calls doSomething of the policy
         this->doSomething();
    }

    // will return useful information
    some_type getSomething();
};

आपको इस उत्तर में इसके लिए एक गैर-आकस्मिक उदाहरण मिलेगा । इसका उपयोग करने वाला एक अन्य कोड इस उत्तर में है। CRTP बेस अपने इस पॉइंटर को कास्ट करता है, जिससे डेटा-मेंबर-पॉइंटर्स का उपयोग करके व्युत्पन्न वर्ग के डेटा-फ़ील्ड्स तक पहुँच प्राप्त की जा सके।


नमस्ते, जब मैं आपके CRTP को आज़माता हूं तो मुझे एक सिंटैक्स त्रुटि (xcode 4 में) मिलती है। Xcode का मानना ​​है कि मैं एक क्लास टेम्पलेट को इनहेरिट करने की कोशिश कर रहा हूं। पर त्रुटि होती है P<C>में template<template<typename> class P> class C : P<C> {};उन्होंने कहा कि "वर्ग टेम्पलेट सी का प्रयोग टेम्पलेट तर्क की आवश्यकता है"। क्या आपने वही समस्याएं ली हैं या शायद कोई समाधान जानते हैं?
बेनेदिच

पहली नज़र में @bennedich, जो आपको अपर्याप्त C ++ सुविधा समर्थन के साथ त्रुटि की तरह दिखता है। जो संकलक के बीच बहुत आम है। FlexibleClassभीतर के उपयोग का FlexibleClassतात्पर्य अपने प्रकार से होना चाहिए।
यक्क - एडम नेवरामोंट

@ बेनीडिच: क्लास बॉडी के भीतर से क्लास टेम्पलेट के नाम के उपयोग के नियम C ++ 11 के साथ बदल गए। अपने संकलक में C ++ 11 मोड को सक्षम करने का प्रयास करें।
बेन वोइग्ट

विज़ुअल स्टूडियो 2015 में इस पब्लिक को जोड़ें: f () {}; f (int_type t): मान (t) {}; इस संकलक त्रुटि को रोकने के लिए: त्रुटि C2440: '<function-style-cast>': 'utils :: f :: int_type' से 'utils :: f' नोट में परिवर्तित नहीं हो सकता है: कोई भी निर्माता स्रोत प्रकार, या कन्स्ट्रक्टर नहीं ले सकता है अधिभार संकल्प अस्पष्ट था
डेमियन

41

@roo : एनकैप्सुलेशन यहां टूटा नहीं है क्योंकि वर्ग खुद तय करता है कि कौन अपने निजी सदस्यों तक पहुंच सकता है। यदि यह कक्षा के बाहर से हो सकता है, तो एन्कैप्सुलेशन केवल टूट जाएगा, उदाहरण के लिए, यदि आपका operator <<घोषित करता है "मैं कक्षा का दोस्त हूं foo"।

friendके उपयोग की जगह public, का उपयोग नहीं private!

वास्तव में, C ++ FAQ इसका उत्तर पहले से ही देता है


14
"दोस्त ने सार्वजनिक उपयोग की जगह, निजी का उपयोग नहीं किया!", मैं दूसरा कहता हूं
Waleed Eissa

26
@Assaf: हाँ, लेकिन FQA, अधिकांश भाग के लिए है, बिना किसी वास्तविक मूल्य के बहुत सारे असंगत गुस्से में है। पर friendकोई अपवाद नहीं है। यहाँ केवल वास्तविक अवलोकन यह है कि C ++ केवल संकलन-समय पर इनकैप्सुलेशन सुनिश्चित करता है। और आपको इसे कहने के लिए किसी और शब्द की आवश्यकता नहीं है। बाकी बोलचाल है। तो, संक्षेप में: एफक्यूए का यह खंड ध्यान देने योग्य नहीं है।
कोनराड रुडोल्फ

12
उस FQA में से अधिकांश एकदम स्पष्ट है :)
rama-jka toti

1
@Konrad: "यहाँ केवल वास्तविक अवलोकन यह है कि C ++ केवल संकलन-समय पर इनकैप्सुलेशन सुनिश्चित करता है।" क्या कोई भाषा रनटाइम में इसे सुनिश्चित करती है? जहाँ तक मुझे पता है, C #, Java, पायथन और कई अन्य लोगों के लिए निजी सदस्यों (और फ़ंक्शंस, जो फ़ंक्शंस या फ़ंक्शंस के लिए फ़ंक्शंस की अनुमति देते हैं) के लिए निजी संदर्भों का संदर्भ देते हैं।
एंड्री कैरन

@ आंद्रे: जेवीएम और सीएलआर वास्तव में इसे सुनिश्चित कर सकते हैं जहां तक ​​मुझे पता है। मुझे नहीं पता कि यह हमेशा किया जाता है, लेकिन आप इस तरह के घुसपैठ के खिलाफ पैकेज / असेंबली की कथित रूप से रक्षा कर सकते हैं (हालांकि खुद ऐसा कभी नहीं किया है)।
कोनराड रुडोल्फ

27

विहित उदाहरण ऑपरेटर को अधिभारित करने के लिए है <<। एक अन्य आम उपयोग अपने आंतरिक में एक सहायक या व्यवस्थापक वर्ग की अनुमति देने के लिए है।

यहां C ++ मित्रों के बारे में मैंने सुना कुछ दिशानिर्देश हैं। अंतिम एक विशेष रूप से यादगार है।

  • आपके दोस्त आपके बच्चे के दोस्त नहीं हैं।
  • आपके बच्चे के दोस्त आपके दोस्त नहीं हैं।
  • केवल दोस्त ही आपके प्राइवेट पार्ट्स को छू सकते हैं।

" कैनोनिकल उदाहरण ऑपरेटर को अधिभारित करने के लिए है << " friendमैं अनुमान का उपयोग नहीं करने का कैनोनिकल ।
जिज्ञासु

16

संपादित करें: थोड़ी देर के लिए फेक पढ़ना मुझे पसंद है << >> ऑपरेटर ओवरलोडिंग और उन वर्गों के एक दोस्त के रूप में जोड़ना, हालांकि मुझे यकीन नहीं है कि यह कैसे अंतराल को नहीं तोड़ता है

यह अतिक्रमण को कैसे तोड़ेगा?

जब आप किसी डेटा सदस्य को अप्रतिबंधित एक्सेस की अनुमति देते हैं तो आप एनकैप्सुलेशन तोड़ देते हैं । निम्नलिखित वर्गों पर विचार करें:

class c1 {
public:
  int x;
};

class c2 {
public:
  int foo();
private:
  int x;
};

class c3 {
  friend int foo();
private:
  int x;
};

c1है स्पष्ट रूप से समझाया नहीं। कोई भी इसे पढ़ और संशोधित कर सकता xहै। हमारे पास किसी भी प्रकार के अभिगम नियंत्रण को लागू करने का कोई तरीका नहीं है।

c2स्पष्ट रूप से समझाया गया है। कोई सार्वजनिक पहुँच नहीं है x। आप केवल इतना कर सकते हैं कि fooफ़ंक्शन को कॉल किया जाए , जो कक्षा में कुछ सार्थक संचालन करता है ।

c3? क्या यह कम है? क्या यह अप्रतिबंधित पहुँच की अनुमति देता है x? क्या यह अज्ञात कार्यों को एक्सेस करने की अनुमति देता है?

नहीं, यह कक्षा के निजी सदस्यों तक पहुंचने के लिए सटीक रूप से एक फ़ंक्शन की अनुमति देता है । जैसा c2किया वैसा ही किया। और ठीक उसी तरह c2, जिस फ़ंक्शन का एक्सेस है, वह "कुछ यादृच्छिक, अज्ञात फ़ंक्शन" नहीं है, लेकिन "क्लास परिभाषा में सूचीबद्ध फ़ंक्शन" है। जैसे c2, हम देख सकते हैं, सिर्फ कक्षा की परिभाषाओं को देखकर, जिनके पास पूरी सूची है।

तो यह वास्तव में कैसे कम है? समान मात्रा में कोड की कक्षा के निजी सदस्यों तक पहुंच होती है। और हर किसी को किसके पास पहुंच है वर्ग परिभाषा में सूचीबद्ध है।

friendएनकैप्सुलेशन को नहीं तोड़ता है। यह कुछ जावा लोगों के प्रोग्रामर को असहज महसूस कराता है, क्योंकि जब वे "ओओपी" कहते हैं, तो उनका वास्तव में मतलब "जावा" होता है। जब वे "एनकैप्सुलेशन" कहते हैं, तो उनका मतलब यह नहीं है कि "निजी सदस्यों को मनमाने ढंग से पहुंच से संरक्षित किया जाना चाहिए", लेकिन "एक जावा वर्ग जहां केवल निजी सदस्यों तक पहुंचने में सक्षम हैं, वर्ग के सदस्य हैं", भले ही यह पूरी तरह से बकवास है कई कारण

सबसे पहले, जैसा कि पहले ही दिखाया गया है, यह बहुत सीमित है। ऐसा कोई कारण नहीं है कि मित्र विधियों को ऐसा करने की अनुमति न दी जाए।

दूसरा, यह पर्याप्त प्रतिबंधात्मक नहीं है । एक चौथे वर्ग पर विचार करें:

class c4 {
public:
  int getx();
  void setx(int x);
private:
  int x;
};

यह, पूर्वोक्त जावा मानसिकता के अनुसार, पूरी तरह से समझाया गया है। और फिर भी, यह बिल्कुल किसी को भी एक्स को पढ़ने और संशोधित करने की अनुमति देता है । यह भी कैसे समझ में आता है? (संकेत: यह नहीं है)

नीचे पंक्ति: इनकैप्सुलेशन नियंत्रण करने में सक्षम है जो निजी सदस्यों तक पहुंच सकता है। यह ठीक नहीं है जहां इन कार्यों की परिभाषाएं स्थित हैं।


10

एंड्रयू के उदाहरण का एक और सामान्य संस्करण, खूंखार कोड-युगल

parent.addChild(child);
child.setParent(parent);

चिंता के बजाय अगर दोनों लाइनें हमेशा एक साथ की जाती हैं और सुसंगत क्रम में आप तरीकों को निजी बना सकते हैं और एक दोस्त कार्य करना है जिसमें संगत शामिल हैं:

class Parent;

class Object {
private:
    void setParent(Parent&);

    friend void addChild(Parent& parent, Object& child);
};

class Parent : public Object {
private:
     void addChild(Object& child);

     friend void addChild(Parent& parent, Object& child);
};

void addChild(Parent& parent, Object& child) {
    if( &parent == &child ){ 
        wetPants(); 
    }
    parent.addChild(child);
    child.setParent(parent);
}

दूसरे शब्दों में, आप सार्वजनिक इंटरफेस को छोटा रख सकते हैं और ऐसे इंवेरेन्ट को लागू कर सकते हैं जो मित्र कार्यों में कक्षाओं और वस्तुओं को काटते हैं।


6
उसके लिए किसी को एक दोस्त की आवश्यकता क्यों होगी? क्यों नहीं addChildसदस्य समारोह भी माता पिता सेट करें?
नवाज

1
एक बेहतर उदाहरण setParentएक दोस्त बनाना होगा , क्योंकि आप ग्राहकों को माता-पिता को बदलने की अनुमति नहीं देना चाहते हैं क्योंकि आप इसे addChild/ removeChildकार्यों की श्रेणी में प्रबंधित कर रहे हैं ।
यलिसार

8

आप निजी / संरक्षित / सार्वजनिक अधिकार का उपयोग करके सदस्यों और कार्यों के लिए पहुँच अधिकार को नियंत्रित करते हैं? इसलिए उन 3 स्तरों में से प्रत्येक का विचार स्पष्ट है, तो यह स्पष्ट होना चाहिए कि हम कुछ याद कर रहे हैं ...

उदाहरण के लिए संरक्षित सदस्य / कार्य की घोषणा बहुत सामान्य है। आप कह रहे हैं कि यह फ़ंक्शन सभी के लिए पहुंच से बाहर है (पाठ्यक्रम के एक विरासत वाले बच्चे को छोड़कर)। लेकिन अपवादों का क्या? हर सुरक्षा प्रणाली आपको कुछ प्रकार की 'सफ़ेद सूची' देती है?

तो दोस्त आपको रॉक सॉलिड ऑब्जेक्ट आइसोलेशन होने की सुविधा देता है, लेकिन आपको जो चीजें उचित लगती हैं, उनके लिए "लोफोल" बनाने की अनुमति देता है।

मुझे लगता है कि लोग कहते हैं कि इसकी आवश्यकता नहीं है क्योंकि हमेशा एक ऐसा डिज़ाइन होता है जो इसके बिना करेगा। मुझे लगता है कि यह वैश्विक चर की चर्चा के समान है: आपको कभी भी उनका उपयोग नहीं करना चाहिए, उनके बिना हमेशा करने का एक तरीका है ... लेकिन वास्तव में, आप ऐसे मामलों को देखते हैं जहां समाप्त होता है (लगभग) सबसे सुरुचिपूर्ण तरीके से। .. मुझे लगता है कि दोस्तों के साथ भी यही मामला है।

यह वास्तव में कोई अच्छा नहीं करता है, इसके अलावा आपको सेटिंग फ़ंक्शन का उपयोग किए बिना एक सदस्य चर का उपयोग करने देता है

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


2
कैसे friendएक बचाव का रास्ता है? यह कक्षा में सूचीबद्ध विधियों को अपने निजी सदस्यों तक पहुंचने देता है । यह अभी भी मनमाने कोड को उन तक पहुंचने नहीं देता है। जैसे कि यह एक सार्वजनिक सदस्य समारोह से अलग नहीं है।
jalf

दोस्त उतना ही करीब है जितना आप C ++ में C # / Java पैकेज-लेवल एक्सेस प्राप्त कर सकते हैं। @ जैलफ - मित्र वर्गों (जैसे कि कारखाना वर्ग) के बारे में क्या?
Ogre Psalm33

1
@ ऑग्रे: उनके बारे में क्या? आप अभी भी विशेष रूप से उस वर्ग को दे रहे हैं और किसी और को कक्षा के इंटर्नल तक पहुंच नहीं है। आप सिर्फ अपनी कक्षा के साथ पेंच लगाने के लिए अनजान अज्ञात कोड के लिए गेट को खुला नहीं छोड़ रहे हैं।
jalf

8

मुझे मित्र पहुंच का उपयोग करने के लिए आसान जगह मिली: निजी कार्यों में से एक।


लेकिन क्या इसके लिए एक सार्वजनिक समारोह का भी इस्तेमाल किया जा सकता है? मित्र पहुंच का उपयोग करने का क्या फायदा है?
झेंग क्व

@Maverobot क्या आप अपने प्रश्न के बारे में विस्तार से बता सकते हैं?
व्लादिमीर

5

दोस्त तब काम आता है जब आप एक कंटेनर का निर्माण कर रहे होते हैं और आप उस वर्ग के लिए एक पुनरावृति लागू करना चाहते हैं।


4

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

         Game
        /    \
 TwoPlayer  SinglePlayer

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

सच्चाई यह है कि इस पूरे मुद्दे को हमारी प्रणाली के बेहतर कार्यान्वयन द्वारा हल किया जा सकता था लेकिन हमारे पास जो था, उसमें बंद था।


4

संक्षिप्त उत्तर होगा: मित्र का उपयोग करें जब वह वास्तव में सुधार करता है इनकैप्सुलेशन करता है। पठनीयता और प्रयोज्यता में सुधार (संचालक << और >> विहित उदाहरण हैं) भी एक अच्छा कारण है।

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


" ऑपरेटर << और >> विहित उदाहरण हैं " नहीं बल्कि विहित काउंटर उदाहरण हैं
जिज्ञासु

@ कुरसीगू: ऑपरेटर <<और >>सदस्यों के बजाय आमतौर पर दोस्त होते हैं, क्योंकि उन्हें सदस्य बनाने से उनका उपयोग करने में अजीब होता है। बेशक, मैं उस मामले के बारे में बात कर रहा हूं जब उन ऑपरेटरों को निजी डेटा तक पहुंचने की आवश्यकता होती है; अन्यथा, दोस्ती बेकार है।
गोरक्षक

" क्योंकि उन्हें सदस्य बनाना उन्हें उपयोग करने के लिए अजीब बना देगा। " जाहिर है, गैर-सदस्यों के बजाय मूल्य वर्ग के सदस्य बनाना operator<<और बनाना , वांछित सिंटैक्स प्रदान नहीं करेगा, और मैं इसका सुझाव नहीं दे रहा हूं । " मैं उस मामले के बारे में बात कर रहा हूं जब उन ऑपरेटरों को निजी डेटा का उपयोग करने की आवश्यकता होती है " मैं यह नहीं देखता कि इनपुट / आउटपुट ऑपरेटरों को निजी सदस्यों तक पहुंचने की आवश्यकता क्यों होगी। operator>>i|ostream
जिज्ञासु

4

C ++ के निर्माता का कहना है कि किसी भी अतिक्रमण सिद्धांत को तोड़ना नहीं है, और मैं उसे उद्धृत करूंगा:

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

स्पष्ट से अधिक है ...


@ कुरसीगू: टेम्प्लेट के मामले में भी यह सच है।
नवाज

@ नवाज़ टेम्पलेट मित्रता प्रदान की जा सकती है, लेकिन कोई भी मित्र को अनुदान देने वाले वर्ग को संशोधित किए बिना एक नई आंशिक या स्पष्ट विशेषज्ञता बना सकता है। लेकिन जब आप ऐसा करते हैं तो ओडीआर उल्लंघन से सावधान रहें। और वैसे भी ऐसा मत करो।
जिज्ञासु

3

एक अन्य उपयोग: दोस्त (+ वर्चुअल इनहेरिटेंस) का उपयोग एक वर्ग से प्राप्त करने से बचने के लिए किया जा सकता है (उर्फ: "एक कक्षा को कम करने योग्य") => 1 , 2

से 2 :

 class Fred;

 class FredBase {
 private:
   friend class Fred;
   FredBase() { }
 };

 class Fred : private virtual FredBase {
 public:
   ...
 }; 

3

TDD करने के लिए कई बार मैंने C ++ में 'दोस्त' कीवर्ड का उपयोग किया है।

क्या कोई दोस्त मेरे बारे में सब कुछ जान सकता है?


अपडेट किया गया: मुझे Bjarne Stroustrup साइट से "मित्र" कीवर्ड के बारे में यह मूल्यवान उत्तर मिला ।

"मित्र" सदस्यता की तरह ही पहुंच प्रदान करने का एक स्पष्ट तंत्र है।


3

आपको friendकीवर्ड का उपयोग कब / कहाँ करना है , इस बारे में आपको बहुत सावधान रहना होगा , और आपकी तरह, मैंने भी इसका उपयोग बहुत कम किया है। नीचे कुछ friendविकल्पों का उपयोग और विकल्प दिए गए हैं ।

मान लें कि आप दो वस्तुओं की तुलना करके देखना चाहते हैं कि क्या वे समान हैं। आप या तो कर सकते हैं:

  • तुलना करने के लिए एक्सेसर विधियों का उपयोग करें (हर आइवर की जांच करें और समानता का निर्धारण करें)।
  • या, आप सभी सदस्यों को सीधे सार्वजनिक कर सकते हैं।

पहले विकल्प के साथ समस्या यह है कि यह एक्सेसरों का एक बहुत कुछ हो सकता है, जो कि प्रत्यक्ष चर पहुंच से थोड़ा धीमा है, पढ़ने में कठिन है, और बोझिल है। दूसरे दृष्टिकोण के साथ समस्या यह है कि आप पूरी तरह से एनकैप्सुलेशन को तोड़ देते हैं।

क्या अच्छा होगा, अगर हम एक बाहरी कार्य को परिभाषित कर सकते हैं जो अभी भी एक वर्ग के निजी सदस्यों तक पहुंच सकता है। हम friendकीवर्ड के साथ ऐसा कर सकते हैं :

class Beer {
public:
    friend bool equal(Beer a, Beer b);
private:
    // ...
};

विधि equal(Beer, Beer)अब तक सीधी पहुंच है aऔर bके निजी सदस्यों (हो सकता है char *brand, float percentAlcoholआदि यह एक नहीं बल्कि काल्पनिक उदाहरण के लिए, आप जल्दी ही लागू होता है friendएक ओवरलोड करने के लिए == operator, लेकिन हम उस करने के लिए मिल जाएगा।

ध्यान देने योग्य कुछ बातें:

  • A friendवर्ग का सदस्य कार्य नहीं है
  • यह कक्षा के निजी सदस्यों के लिए विशेष पहुंच वाला एक सामान्य कार्य है
  • मित्रों के साथ सभी एक्सेसरों और म्यूटेटर को प्रतिस्थापित न करें (आप सब कुछ कर सकते हैं public!)
  • मित्रता पारस्परिक नहीं है
  • मित्रता सकर्मक नहीं है
  • मित्रता विरासत में नहीं मिली है
  • या, जैसा कि C ++ FAQ बताता है : "सिर्फ इसलिए कि मैं आपको दोस्ती का अधिकार देता हूं, अपने बच्चों को मेरे लिए एक्सेस देने के लिए स्वचालित रूप से नहीं देता, अपने दोस्तों को आप तक पहुंच प्रदान करने के लिए स्वचालित रूप से अनुदान नहीं देता है, और स्वचालित रूप से मुझे आप तक पहुंच प्रदान नहीं करता है। । "

मैं केवल वास्तव में उपयोग करता हूं friendsजब इसे दूसरे तरीके से करना बहुत कठिन होता है। एक और उदाहरण के रूप में, कई वेक्टर गणित कार्यों अक्सर के रूप में बनाई गई हैं friendsकी अंतर की वजह से Mat2x2, Mat3x3, Mat4x4, Vec2, Vec3, Vec4, आदि और यह दोस्त होने के बजाय, हर जगह accessors उपयोग करने के लिए बस इतना आसान है। जैसा कि बताया गया है, friendअक्सर लागू होने पर <<(डिबगिंग के लिए वास्तव में उपयोगी) लागू होता है ,>> और शायद ==ऑपरेटर के लिए लागू किया जाता है, लेकिन इसके लिए कुछ के लिए भी इस्तेमाल किया जा सकता है:

class Birds {
public:
    friend Birds operator +(Birds, Birds);
private:
    int numberInFlock;
};


Birds operator +(Birds b1, Birds b2) {
    Birds temp;
    temp.numberInFlock = b1.numberInFlock + b2.numberInFlock;
    return temp;
}

जैसा कि मैं कहता हूं, मैं friendबहुत बार उपयोग नहीं करता हूं , लेकिन हर अब और फिर यह सिर्फ वही है जो आपको चाहिए। उम्मीद है की यह मदद करेगा!


2

ऑपरेटर के संबंध में << और ऑपरेटर >> इन ऑपरेटरों को दोस्त बनाने का कोई अच्छा कारण नहीं है। यह सच है कि उन्हें सदस्य कार्य नहीं करने चाहिए, लेकिन उन्हें मित्र होने की आवश्यकता नहीं है।

सबसे अच्छी बात यह है कि सार्वजनिक प्रिंट (ओस्ट्रीम और) और रीड (आईएसट्रीम और) फ़ंक्शन बनाएं। फिर, उन कार्यों के संदर्भ में ऑपरेटर << और ऑपरेटर >> लिखें। यह आपको उन कार्यों को आभासी बनाने की अनुमति देने का अतिरिक्त लाभ देता है, जो आभासी क्रमांकन प्रदान करता है।


" ऑपरेटर के संबंध में << और ऑपरेटर >> इन ऑपरेटरों को दोस्त बनाने का कोई अच्छा कारण नहीं है। " बिल्कुल सही। " यह आपको उन कार्यों को आभासी बनाने की अनुमति देने का अतिरिक्त लाभ देता है, " यदि प्रश्न में वर्ग व्युत्पत्ति के लिए अभिप्रेत है, तो हाँ। नहीं तो परेशान क्यों?
जिज्ञासु

मैं वास्तव में नहीं मिलता कि इस उत्तर को दो बार क्यों नकार दिया गया - और बिना स्पष्टीकरण के भी! वो असभ्य हैं।
जिज्ञासु

आभासी एक
परिपूर्ण

2

मैं केवल मित्र-कीवर्ड का उपयोग सुरक्षित सुरक्षा कार्यों के लिए कर रहा हूं। कुछ कहेंगे कि आपको संरक्षित कार्यक्षमता का परीक्षण नहीं करना चाहिए। हालाँकि, नई कार्यक्षमता जोड़ते समय मुझे यह बहुत उपयोगी उपकरण लगता है।

हालाँकि, मैं कक्षा की घोषणाओं में सीधे कीवर्ड का उपयोग नहीं करता, इसके बजाय मैं इसे प्राप्त करने के लिए एक निफ्टी टेम्पलेट-हैक का उपयोग करता हूं:

template<typename T>
class FriendIdentity {
public:
  typedef T me;
};

/**
 * A class to get access to protected stuff in unittests. Don't use
 * directly, use friendMe() instead.
 */
template<class ToFriend, typename ParentClass>
class Friender: public ParentClass
{
public:
  Friender() {}
  virtual ~Friender() {}
private:
// MSVC != GCC
#ifdef _MSC_VER
  friend ToFriend;
#else
  friend class FriendIdentity<ToFriend>::me;
#endif
};

/**
 * Gives access to protected variables/functions in unittests.
 * Usage: <code>friendMe(this, someprotectedobject).someProtectedMethod();</code>
 */
template<typename Tester, typename ParentClass>
Friender<Tester, ParentClass> & 
friendMe(Tester * me, ParentClass & instance)
{
    return (Friender<Tester, ParentClass> &)(instance);
}

यह मुझे निम्नलिखित करने में सक्षम बनाता है:

friendMe(this, someClassInstance).someProtectedFunction();

जीसीसी और एमएसवीसी कम से कम काम करता है।


2

C ++ में "मित्र" कीवर्ड ऑपरेटर ओवरलोडिंग और मेकिंग ब्रिज में उपयोगी है।

1.) ऑपरेटर ओवरलोडिंग में फ्रेंड कीवर्ड: ऑपरेटर ओवरलोडिंग के
लिए उदाहरण है: मान लें कि हमारे पास एक क्लास "प्वाइंट" है जिसमें दो फ्लोट वेरिएबल
"x" (x- कॉर्डिनेट के लिए) और "y" (y- कोऑर्डिनेट के लिए) है। अब हमें ओवरलोड "<<"(निष्कर्षण ऑपरेटर) को इस तरह से करना है कि अगर हम कॉल करते हैं "cout << pointobj"तो यह x और y समन्वय करेगा (जहां पॉइंटोबज क्लास प्वाइंट का ऑब्जेक्ट है)। ऐसा करने के लिए हमारे पास दो विकल्प हैं:

   1. अधिभार "ऑपरेटर << ()" फ़ंक्शन "ओस्ट्रीम" कक्षा में।
   2. "अधिभार" ऑपरेटर << () "फ़ंक्शन" बिंदु "वर्ग में।
अब पहला विकल्प अच्छा नहीं है क्योंकि अगर हमें कुछ अलग वर्ग के लिए इस ऑपरेटर को फिर से अधिभारित करने की आवश्यकता है तो हमें फिर से "ओस्ट्रीम" वर्ग में बदलाव करना होगा।
इसलिए दूसरा सबसे अच्छा विकल्प है। अब संकलक "operator <<()"फ़ंक्शन को कॉल कर सकता है:

   1. आस्ट्रीम ऑबजेक्ट वस्तु cout.As: cout.operator << (प्वाइंटबॉज) (फॉर्म ओस्ट्रीम क्लास)। 
एक वस्तु के बिना 2.Call। एस: ऑपरेटर << (कटआउट, प्वाइंटबॉज) (प्वाइंट क्लास से)।

बीकॉज हमने प्वाइंट क्लास में ओवरलोडिंग को लागू किया है। तो इस फ़ंक्शन को बिना ऑब्जेक्ट के कॉल करने के लिए "friend"हमें कीवर्ड जोड़ना होगा क्योंकि हम किसी ऑब्जेक्ट के बिना किसी फ़ंक्शन को कॉल कर सकते हैं। अब फंक्शन डिक्लेरेशन इस प्रकार होगा:
"friend ostream &operator<<(ostream &cout, Point &pointobj);"

2.) ब्रिज बनाने में फ्रेंड कीवर्ड:
मान लीजिए कि हमें एक फंक्शन करना है, जिसमें हमें दो या दो से अधिक क्लासेस के प्राइवेट मेंबर को एक्सेस करना होगा (जिसे आमतौर पर "ब्रिज" कहा जाता है)। यह कैसे करें:
किसी वर्ग के निजी सदस्य तक पहुँचने के लिए उस वर्ग का सदस्य होना चाहिए। अब अन्य वर्ग के निजी सदस्य तक पहुँचने के लिए हर वर्ग को उस फंक्शन को फ्रेंड फंक्शन घोषित करना चाहिए। उदाहरण के लिए: मान लीजिए कि दो वर्ग ए और बी हैं। एक समारोह "funcBridge()"दोनों वर्गों के निजी सदस्य तक पहुंचना चाहता है। फिर दोनों वर्ग को इस प्रकार घोषित करना चाहिए "funcBridge()":
friend return_type funcBridge(A &a_obj, B & b_obj);

मुझे लगता है कि इससे मित्र कीवर्ड को समझने में मदद मिलेगी।


2

जैसा कि मित्र घोषणा के संदर्भ में कहा गया है:

मित्र घोषणा एक वर्ग निकाय में दिखाई देती है और एक फ़ंक्शन या किसी अन्य वर्ग की पहुंच उस कक्षा के निजी और संरक्षित सदस्यों तक पहुँचती है जहाँ मित्र घोषणा प्रकट होती है।

तो बस एक अनुस्मारक के रूप में, कुछ उत्तरों में तकनीकी त्रुटियां हैं जो कहती हैं कि friendकेवल संरक्षित सदस्यों का दौरा कर सकती हैं।


1

पेड़ का उदाहरण एक बहुत अच्छा उदाहरण है: एक विरासत संबंध के बिना कुछ अलग वर्ग में लागू की गई वस्तु।

हो सकता है कि आपको अपने "मित्र" कारखाने का उपयोग करने के लिए एक निर्माता की रक्षा करने और लोगों को मजबूर करने के लिए भी इसकी आवश्यकता हो।

... ठीक है, अच्छी तरह से स्पष्ट रूप से आप इसके बिना रह सकते हैं।


1

TDD करने के लिए कई बार मैंने C ++ में 'दोस्त' कीवर्ड का उपयोग किया है।
क्या कोई दोस्त मेरे बारे में सब कुछ जान सकता है?

नहीं, इसका केवल एक ही तरीका है दोस्ती: `(


1

एक विशिष्ट उदाहरण जहां मैं उपयोग करता हूं friendवह सिंगलटन क्लासेस बनाते समय है । friendकीवर्ड मुझे एक्सेसर समारोह है, जो हमेशा वर्ग पर एक "GetInstance ()" विधि की तुलना में अधिक संक्षिप्त है बना सकते हैं।

/////////////////////////
// Header file
class MySingleton
{
private:
    // Private c-tor for Singleton pattern
    MySingleton() {}

    friend MySingleton& GetMySingleton();
}

// Accessor function - less verbose than having a "GetInstance()"
//   static function on the class
MySingleton& GetMySingleton();


/////////////////////////
// Implementation file
MySingleton& GetMySingleton()
{
    static MySingleton theInstance;
    return theInstance;
}

यह स्वाद का मामला हो सकता है, लेकिन मुझे नहीं लगता कि कुछ कीस्ट्रोक्स को सहेजना यहां दोस्त के उपयोग को सही ठहराता है। GetMySingleton () कक्षा का एक स्थिर तरीका होना चाहिए।
गोरक्षक

निजी सी-टोर, MySingleton को तुरंत चलाने के लिए एक गैर-मित्र फ़ंक्शन को समाप्त कर देगा, इसलिए मित्र कीवर्ड की यहाँ आवश्यकता है।
JBRWilkinson

@ गोरिक " यह स्वाद का मामला हो सकता है, लेकिन मुझे नहीं लगता कि कुछ कीस्ट्रोक्स को बचाने से यहां दोस्त का इस्तेमाल जायज है। " वैसे भी, friendकरता नहीं एक विशेष "औचित्य" की जरूरत है, जब एक सदस्य समारोह जोड़ने नहीं करता है।
जिज्ञासु

सिंगलेट्स को वैसे भी एक बुरा अभ्यास माना जाता है (Google "सिंगलटन हानिकारक" और आपको इस तरह के बहुत सारे परिणाम मिलेंगे । मुझे नहीं लगता कि
एंटीपैटर्न

1

फ्रेंड फ़ंक्शंस और कक्षाएं सामान्य मामले में टूटने से बचने के लिए कक्षा के निजी और संरक्षित सदस्यों तक सीधे पहुंच प्रदान करती हैं। अधिकांश उपयोग ओस्ट्रीम के साथ है: हम टाइप करने में सक्षम होना चाहते हैं:

Point p;
cout << p;

हालांकि, इसके लिए प्वाइंट के निजी डेटा तक पहुंच की आवश्यकता हो सकती है, इसलिए हम ओवरलोड ऑपरेटर को परिभाषित करते हैं

friend ostream& operator<<(ostream& output, const Point& p);

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

यदि आप मित्र को कक्षा के विस्तार के रूप में देखते हैं, तो यह एक मुद्दा नहीं है, तार्किक रूप से बोल रहा है। लेकिन, उस मामले में, दोस्त को पहले स्थान पर बाहर निकालना क्यों आवश्यक था।

उसी चीज़ को प्राप्त करने के लिए जिसे 'मित्रों का उद्देश्य' प्राप्त करना है, लेकिन बिना इनकैप्सुलेशन को तोड़े, कोई भी ऐसा कर सकता है:

class A
{
public:
    void need_your_data(B & myBuddy)
    {
        myBuddy.take_this_name(name_);
    }
private:
    string name_;
};

class B
{
public:
    void print_buddy_name(A & myBuddy)
    {
        myBuddy.need_your_data(*this);
    }
    void take_this_name(const string & name)
    {
        cout << name;
    }
}; 

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

मुझे लगता है कि 'मित्र' का उपयोग करना, केवल लाभकारी लाभ के साथ एक शॉर्टकट है, लेकिन निश्चित लागत है।


1

यह वास्तविक उपयोग की स्थिति नहीं हो सकती है, लेकिन कक्षाओं के बीच दोस्त के उपयोग को स्पष्ट करने में मदद कर सकती है।

द क्लबहाउस

class ClubHouse {
public:
    friend class VIPMember; // VIP Members Have Full Access To Class
private:
    unsigned nonMembers_;
    unsigned paidMembers_;
    unsigned vipMembers;

    std::vector<Member> members_;
public:
    ClubHouse() : nonMembers_(0), paidMembers_(0), vipMembers(0) {}

    addMember( const Member& member ) { // ...code }   
    void updateMembership( unsigned memberID, Member::MembershipType type ) { // ...code }
    Amenity getAmenity( unsigned memberID ) { // ...code }

protected:
    void joinVIPEvent( unsigned memberID ) { // ...code }

}; // ClubHouse

सदस्यों का वर्ग

class Member {
public:
    enum MemberShipType {
        NON_MEMBER_PAID_EVENT,   // Single Event Paid (At Door)
        PAID_MEMBERSHIP,         // Monthly - Yearly Subscription
        VIP_MEMBERSHIP,          // Highest Possible Membership
    }; // MemberShipType

protected:
    MemberShipType type_;
    unsigned id_;
    Amenity amenity_;
public:
    Member( unsigned id, MemberShipType type ) : id_(id), type_(type) {}
    virtual ~Member(){}
    unsigned getId() const { return id_; }
    MemberShipType getType() const { return type_; }
    virtual void getAmenityFromClubHouse() = 0       
};

class NonMember : public Member {
public:
   explicit NonMember( unsigned id ) : Member( id, MemberShipType::NON_MEMBER_PAID_EVENT ) {}   

   void getAmenityFromClubHouse() override {
       Amenity = ClubHouse::getAmenity( this->id_ );
    }
};

class PaidMember : public Member {
public:
    explicit PaidMember( unsigned id ) : Member( id, MemberShipType::PAID_MEMBERSHIP ) {}

    void getAmenityFromClubHouse() override {
       Amenity = ClubHouse::getAmenity( this->id_ );
    }
};

class VIPMember : public Member {
public:
    friend class ClubHouse;
public:
    explicit VIPMember( unsigned id ) : Member( id, MemberShipType::VIP_MEMBERSHIP ) {}

    void getAmenityFromClubHouse() override {
       Amenity = ClubHouse::getAmenity( this->id_ );
    }

    void attendVIPEvent() {
        ClubHouse::joinVIPEvent( this->id );
    }
};

आराम

class Amenity{};

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

हालाँकि, सदस्यों और उसके व्युत्पन्न वर्गों के इस प्रकार के पदानुक्रम के माध्यम से और क्लबहाउस क्लास के साथ उनके संबंध व्युत्पन्न वर्ग का एकमात्र है जिसमें "विशेष विशेषाधिकार" हैं, जो VIPMember वर्ग है। बेस क्लास और अन्य 2 व्युत्पन्न वर्ग, क्लबहाउस की जॉइनवीपेंट () पद्धति का उपयोग नहीं कर सकते हैं, फिर भी वीआईपी सदस्य वर्ग को यह विशेषाधिकार प्राप्त है जैसे कि उस घटना तक उसकी पूरी पहुंच है।

तो VIPMember और ClubHouse के साथ, यह दो तरह से पहुंच मार्ग है जहां अन्य सदस्य वर्ग सीमित हैं।


0

क्लास के लिए ट्री एल्गोरिदम को लागू करते समय, रूपरेखा कोड ने हमें नोड क्लास के दोस्त के रूप में ट्री क्लास दिया।

यह वास्तव में कोई अच्छा काम नहीं करता है, इसके अलावा आपको सेटिंग फ़ंक्शन का उपयोग किए बिना एक सदस्य चर का उपयोग करने देता है।


0

आप दोस्ती का उपयोग तब कर सकते हैं जब विभिन्न वर्ग (दूसरे से एक को विरासत में नहीं मिला) दूसरे वर्ग के निजी या संरक्षित सदस्यों का उपयोग कर रहे हों।

मित्र कार्यों के विशिष्ट उपयोग के मामले ऐसे ऑपरेशन हैं जो दोनों के निजी या संरक्षित सदस्यों तक पहुंचने वाले दो अलग-अलग वर्गों के बीच किए जाते हैं।

से http://www.cplusplus.com/doc/tutorial/inheritance/

आप इस उदाहरण को देख सकते हैं जहां गैर-सदस्य विधि किसी वर्ग के निजी सदस्यों तक पहुंचती है। इस पद्धति को इस कक्षा में कक्षा के मित्र के रूप में घोषित किया जाना है।

// friend functions
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    Rectangle() {}
    Rectangle (int x, int y) : width(x), height(y) {}
    int area() {return width * height;}
    friend Rectangle duplicate (const Rectangle&);
};

Rectangle duplicate (const Rectangle& param)
{
  Rectangle res;
  res.width = param.width*2;
  res.height = param.height*2;
  return res;
}

int main () {
  Rectangle foo;
  Rectangle bar (2,3);
  foo = duplicate (bar);
  cout << foo.area() << '\n';
  return 0;
}

0

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


-1

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

लेकिन यहां तक ​​कि C # में एक आंतरिक दृश्यता कीवर्ड है और जावा में कुछ चीजों के लिए अपने डिफ़ॉल्ट पैकेज स्तर की पहुंच है। C ++ वास्तव में न्यूनतम वर्ग द्वारा OOP के आदर्श के करीब आता है जो एक वर्ग में दृश्यता का समझौता सटीक रूप से निर्दिष्ट करता है जिसे अन्य वर्ग और केवल अन्य वर्ग इसमें देख सकते हैं।

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

लेकिन फिर वहाँ है InternalsVoubleTo विशेषता (otherAssembly) जो एक क्रॉस-असेंबली मित्र तंत्र की तरह कार्य करता है। Microsoft दृश्य डिजाइनर असेंबलियों के लिए इसका उपयोग करता है ।


-1

मित्र कॉलबैक के लिए भी उपयोगी होते हैं। आप स्थैतिक विधियों के रूप में कॉलबैक लागू कर सकते हैं

class MyFoo
{
private:
    static void callback(void * data, void * clientData);
    void localCallback();
    ...
};

जहां आंतरिक रूप से callbackकॉल localCallbackकरता है, और clientDataइसमें आपका उदाहरण है। मेरी राय में,

या ...

class MyFoo
{
    friend void callback(void * data, void * callData);
    void localCallback();
}

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

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

हेडर में:

class MyFooPrivate;
class MyFoo
{
    friend class MyFooPrivate;
public:
    MyFoo();
    // Public stuff
private:
    MyFooPrivate _private;
    // Other private members as needed
};

सीपीपी में,

class MyFooPrivate
{
public:
   MyFoo *owner;
   // Your complexity here
};

MyFoo::MyFoo()
{
    this->_private->owner = this;
}

यह उन चीजों को छिपाना आसान हो जाता है जो डाउनस्ट्रीम को इस तरह से देखने की जरूरत नहीं है।


1
इंटरफेस इसे प्राप्त करने के लिए एक क्लीनर तरीका नहीं होगा? MyFooPStreet.h पर किसी को देखने से रोकने के लिए क्या है?
JBRWilkinson

1
यदि आप गुप्त रखने के लिए निजी और सार्वजनिक उपयोग कर रहे हैं, तो आप आसानी से हार जाएंगे। "छुपाने" से मेरा मतलब है, MyFoo के उपयोगकर्ता को वास्तव में निजी सदस्यों को देखने की आवश्यकता नहीं है। इसके अलावा, यह एबीआई संगतता बनाए रखने के लिए उपयोगी है। यदि आप _pStreet को पॉइंटर बनाते हैं, तो निजी कार्यान्वयन सार्वजनिक इंटरफ़ेस को स्पर्श किए बिना, जितना चाहें उतना बदल सकता है, जिससे ABI संगतता बनी रहे।
शश

आप PIMPL मुहावरे की बात कर रहे हैं; जिस उद्देश्य के लिए आप कह रहे हैं जैसे अतिरिक्त एनकैप्सुलेशन नहीं है, लेकिन कार्यान्वयन विवरण को हेडर से बाहर ले जाने के लिए ताकि कार्यान्वयन विवरण को बदलना क्लाइंट कोड के पुनर्संयोजन को मजबूर न करे। इसके अलावा, इस मुहावरे को लागू करने के लिए मित्र का उपयोग करने की कोई आवश्यकता नहीं है।
वेबर

सही है। इसका मुख्य उद्देश्य कार्यान्वयन विवरणों को स्थानांतरित करना है। दोस्त वहाँ सार्वजनिक वर्ग के अंदर निजी सदस्यों को निजी या दूसरे तरीके से संभालने के लिए उपयोगी है।
शश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.