सार आधार कक्षाएं और कॉपी निर्माण, अंगूठे के नियम


10

अक्सर बार वस्तु के इंटरफ़ेस को अलग करने के लिए एक सार आधार वर्ग होना एक अच्छा विचार है।

समस्या यह है कि प्रतिलिपि निर्माण, IMHO, C ++ में डिफ़ॉल्ट रूप से बहुत अधिक टूट गया है, कॉपी निर्माणकर्ताओं द्वारा डिफ़ॉल्ट रूप से उत्पन्न किया जा रहा है।

तो, क्या है जब आप एक सार आधार वर्ग और व्युत्पन्न वर्गों में कच्चे संकेत है?

class IAbstract
{
    ~IAbstract() = 0;
}

class Derived : public IAbstract
{
    char *theProblem;
    ...
}

IAbstract *a1 = new Derived();
IAbstract a2 = *a1;//???

और अब क्या आप पूरे पदानुक्रम के लिए प्रतिलिपि निर्माण को साफ-सुथरी रूप से अक्षम करते हैं? निजी के रूप में कॉपी निर्माण की घोषणा करें IAbstract?

क्या सार आधार कक्षाओं के साथ तीन के कोई नियम हैं?



@ tp1: या कम से कम कुछ स्मार्ट पॉइंटर।
बेंजामिन बन्नियर

1
कभी-कभी आपको बस मौजूदा कोड के साथ काम करना पड़ता है ... आप एक पल में सब कुछ नहीं बदल सकते।
कोडर

आपको क्या लगता है कि डिफॉल्ट कॉपी कंस्ट्रक्टर टूट गया है?
B:08овиЈ

2
@ कोडर: Google शैली मार्गदर्शिका कबाड़ का ढेर है और किसी भी C ++ विकास के लिए बिल्कुल बेकार है।
डेडएमजी

जवाबों:


6

एक अमूर्त वर्ग पर कॉपी निर्माण को ज्यादातर मामलों में निजी बनाया जाना चाहिए, साथ ही साथ असाइनमेंट ऑपरेटर भी।

सार वर्ग, परिभाषा के अनुसार, एक बहुरूपी प्रकार है। इसलिए आप नहीं जानते कि आपका उदाहरण कितनी मेमोरी का उपयोग कर रहा है, और इसलिए इसे सुरक्षित रूप से कॉपी या असाइन नहीं किया जा सकता है। व्यवहार में, आप जोखिम को कम करते हैं: /programming/274626/what-is-the-slicing-problem-in-c

C ++ में पॉलीमॉर्फिक प्रकार, मूल्य द्वारा हेरफेर नहीं किया जाना चाहिए। आप उन्हें संदर्भ या पॉइंटर (या किसी स्मार्ट पॉइंटर) से जोड़ते हैं।

यही कारण है कि जावा ने केवल संदर्भ द्वारा वस्तु को जोड़-तोड़ किया है, और क्यों सी # और डी को वर्गों और संरचनाओं (पहले एक बहुरूपिक और संदर्भ प्रकार, दूसरा गैर बहुरूपी और मूल्य प्रकार) होने के बीच अलगाव है।


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

3
भावहीन। यह एक गैर-समस्या है- जो कोई भी C ++ जानता है वह इस गलती को नहीं करेगा। इससे भी महत्वपूर्ण बात यह है कि यदि आप जानते हैं कि आप क्या कर रहे हैं, तो मूल्य द्वारा पॉलीमॉर्फिक प्रकारों में हेरफेर करने का कोई कारण नहीं है। आप एक तकनीकी रूप से पतली संभावना पर कुल घुटने-झटका प्रतिक्रिया शुरू कर रहे हैं। NULL पॉइंटर्स एक बड़ी समस्या है।
डेडएमजी

8

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


और अगर कोई सार है -> Derived1 -> Derived2 पदानुक्रम, और Derived2 Derived1 को सौंपा है? भाषा के ये गहरे कोने मुझे अभी भी आश्चर्यचकित करते हैं।
कोडर

@ कोडर: यह आमतौर पर PEBKAC के रूप में देखा जाता है। हालाँकि, और अधिक सीधे, तो आप हमेशा एक निजी घोषित कर सकता है operator=(const Derived2&)में Derived1
डेडएमजी

ठीक है, शायद यह वास्तव में एक मुद्दा नहीं है। मैं सिर्फ यह सुनिश्चित करना चाहता हूं कि दुरुपयोग के खिलाफ वर्ग सुरक्षित हो।
कोडर

2
और इसके लिए आपको पदक मिलना चाहिए।
वर्ल्ड इंजीनियर

2
@ कोडर: गाली किसके द्वारा? सबसे अच्छा आप कर सकते हैं सही कोड लिखना आसान है। यह उन प्रोग्रामर्स के खिलाफ बचाव की कोशिश करने के लिए व्यर्थ है जो C ++ नहीं जानते हैं।
केविन क्लाइन

2

Ctor और असाइनमेंट को निजी बनाकर (या उन्हें C ++ 11 में हटाकर) घोषित करके आप कॉपी को निष्क्रिय कर देते हैं।

यहाँ मुद्दा यह है कि आपको क्या करना है। अपने कोड के साथ रहने के लिए, IAbstract कोई समस्या नहीं है। (ध्यान दें कि आपने क्या किया था, आप *a1 IAbstractसबबॉजेक्ट को a2 में असाइन करते हैं , किसी भी संदर्भ को खो देते हैं Derived। मान असाइनमेंट पॉलिमॉर्फिक नहीं है)

मुद्दे के साथ आता है Derived::theproblem। वास्तव में एक व्युत्पन्न को कॉपी करना *theproblemडेटा को साझा कर सकता है जिसे साझा करने के लिए डिज़ाइन नहीं किया जा सकता है (दो उदाहरण हैं जो delete theproblemउनके विनाशकर्ता में कॉल कर सकते हैं )।

अगर ऐसा है, तो यह है Derivedकि गैर-प्रतिलिपि योग्य होना चाहिए और असाइन करने योग्य नहीं होना चाहिए। बेशक, अगर आप निजी कॉपी को अंदर IAbstractसे कॉपी करते Derivedहैं, तो Derivedइसकी जरूरत के लिए डिफ़ॉल्ट कॉपी भी कॉपी नहीं होगी। लेकिन अगर आप अपने खुद Derived::Derived(const Derived&)के फोन को IAbtractकॉपी के बिना परिभाषित करते हैं , तो आप उन्हें कॉपी कर सकते हैं।

समस्या व्युत्पन्न में है, और समाधान को व्युत्पन्न में रहना चाहिए: यदि यह केवल बिंदुओं या संदर्भों द्वारा पहुँचा गया एक गतिशील-एकमात्र ऑब्जेक्ट होना चाहिए, तो यह व्युत्पन्न ही है जो होना चाहिए

class Derived
{
    ...
    Derived(const Derived&) = delete;
    Derived& operator=(const Derived&) = delete;
};

अनिवार्य रूप से यह व्युत्पन्न वर्ग के डिजाइनर पर निर्भर है (यह जानना चाहिए कि व्युत्पन्न कैसे काम करता है और कैसे theproblemप्रबंधित किया जाता है) यह तय करने के लिए कि असाइनमेंट और कॉपी के साथ क्या करना है।

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