C++ में प्राइवेट कॉपी कंस्ट्रक्टर का क्या उपयोग है




copy-constructor assignment-operator (5)

लोग निजी कॉपी कंस्ट्रक्टर को क्यों परिभाषित करते हैं?

जब कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटर निजी एक अच्छा डिजाइन बना रहा है?

यदि कक्षा में कोई सदस्य नहीं हैं जो एक अनोखी वस्तु (जैसे फ़ाइल नाम) के संकेत या हैंडल हैं, तो वाट अन्य मामले हैं जहां निजी प्रतिलिपि निर्माता एक अच्छा विचार है?

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


" वर्चुअल कंस्ट्रक्टर मुहावरा " एक महत्वपूर्ण मामला है जहां एक निजी या संरक्षित कॉपी कंस्ट्रक्टर की आवश्यकता होती है। C ++ में एक समस्या उत्पन्न होती है जहां आपको एक बेस क्लास के लिए पॉइंटर दिया जाता है, एक ऑब्जेक्ट का जो वास्तव में इस बेस क्लास से विरासत में मिला है, और आप इसकी एक कॉपी बनाना चाहते हैं। कॉपी कंस्ट्रक्टर को कॉल करने से इनहेरिटिंग क्लास के कॉपी कंस्ट्रक्टर को कॉल नहीं किया जाएगा, लेकिन वास्तव में बेस क्लास के कॉपी कंस्ट्रक्टर को कॉल करें।

का निरीक्षण करें:

class Base {

public:
   Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};

class Derived : public Base {

public:
   Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}

Base * obj = new Derived;
Base * obj2 = new Derived(*obj);

उपरोक्त कोड आउटपुट का उत्पादन करेगा:

"Base copy constructor"

यह स्पष्ट रूप से व्यवहार नहीं है जो प्रोग्रामर चाहता था! प्रोग्रामर "व्युत्पन्न" प्रकार के ऑब्जेक्ट को कॉपी करने का प्रयास कर रहा था, लेकिन बदले में "बेस" प्रकार की एक वस्तु वापस मिल गई !!

समस्या को पूर्वोक्त मुहावरे का उपयोग करके ठीक किया जाता है। ऊपर लिखे उदाहरण को ध्यान से देखें, इस मुहावरे का उपयोग करने के लिए फिर से लिखा गया है:

class Base {

public:
  virtual Base * clone () const = 0; //this will need to be implemented by derived class

protected:
   Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};

class Derived : public Base {

public:
  virtual Base * clone () const {

    //call private copy constructor of class "Derived"
    return static_cast<Base *>( new Derived(*this) );
  }

//private copy constructor:
private:
   Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}

Base * obj = new Derived;
Base * obj2 = obj->clone();

उपरोक्त कोड आउटपुट का उत्पादन करेगा:

"Base copy constructor"
"Derived copy constructor"

दूसरे शब्दों में, इच्छित वस्तु "व्युत्पन्न" का निर्माण किया गया था, न कि "आधार" प्रकार का!

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


आप एक कॉपी कंस्ट्रक्टर का उपयोग करके कक्षा के कुछ तरीकों को लागू करना चाह सकते हैं, लेकिन इसे कक्षा के बाहर उजागर नहीं करना चाहते। तो आप इसे निजी बनाते हैं। किसी अन्य विधि की तरह।


एक बहुत बुरा उदाहरण:

class Vehicle : { int wheels; Vehicle(int w) : wheels(w) {} }

class Car : public Vehicle { Engine * engine; public Car(Engine * e) : Vehicle(4), engine(e) }

...

Car c(new Engine());

Car c2(c); // Now both cars share the same engine!

Vehicle v;
v = c; // This doesn't even make any sense; all you have is a Vehicle with 4 wheels but no engine.

कार को "कॉपी" करने का क्या मतलब है? (क्या एक कार एक कार मॉडल है, या एक कार का एक उदाहरण है? क्या इसे कॉपी करने से वाहन पंजीकरण सुरक्षित रहता है?)

किसी दूसरे को वाहन सौंपने का क्या मतलब है?

यदि ऑपरेशन अर्थहीन हैं (या केवल अनइम्प्लीमेंट किए गए हैं), तो मानक बात यह है कि कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटर को निजी बनाना है, यदि वे अजीब व्यवहार के बजाय उपयोग किए जाते हैं तो एक संकलित त्रुटि पैदा करते हैं।


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

एक और उपयोग एक आभासी फ़ंक्शन के माध्यम से नकल को लागू करने के लिए है। चूंकि कंस्ट्रक्टर virtual नहीं हो सकते हैं, एक सामान्य अभ्यास कॉपी कंस्ट्रक्टर तक सीधी पहुंच को रोकने और एक virtual Base* clone() विधि प्रदान करना है जो वास्तविक रन-टाइम प्रकार की एक प्रति लौटाता है जिससे एक पॉइंटर पॉइंट मिलता है। यह आकस्मिक स्लाइसिंग को रोकता है जो Base b(derived) प्रदर्शित करेगा।

एक अन्य उदाहरण: एक मृत-सरल स्मार्ट पॉइंटर ऑब्जेक्ट जो कि पॉइंटर में दिए गए पॉइंटर को बस हटा देता है: यदि यह संदर्भ गिनती या कई मालिकों को संभालने के कुछ अन्य तरीके का समर्थन नहीं करता है, और जोखिम रहित अनजाने std::auto_ptr नहीं चाहता है std::auto_ptr स्वामित्व की std::auto_ptr हस्तांतरण शैली, फिर बस कॉपी निर्माता को छुपाने से बहुत कम स्मार्ट पॉइंटर मिलता है जो सीमित मामलों के लिए तेज और कुशल है जहां यह प्रयोग करने योग्य है। इसे कॉपी करने के प्रयास के बारे में एक संकलन समय त्रुटि प्रभावी रूप से प्रोग्रामर से पूछेगा "अरे - यदि आप वास्तव में ऐसा करना चाहते हैं तो मुझे एक साझा पॉइंटर में बदल दें, अन्यथा वापस!"।


यहां तक ​​कि अगर ऑब्जेक्ट की सामग्री पॉइंटर्स या अन्य संदर्भ नहीं हैं, तो लोगों को ऑब्जेक्ट को कॉपी करने से रोकना अभी भी उपयोगी हो सकता है। शायद वर्ग में बहुत अधिक डेटा होता है, और प्रतिलिपि बनाना किसी ऑपरेशन का बहुत भारी होना है।





assignment-operator