2010-01-19 10 views
9
class X 
{ 
protected: 
    void protectedFunction() { cout << "I am protected" ; } 
}; 

class Y : public X 
{ 
public: 
    using X::protectedFunction; 
}; 

int main() 
{ 
    Y y1; 
    y1.protectedFunction(); 
} 

इस तरह मैं बेस क्लास के कार्यों में से किसी एक को बेनकाब करने में सक्षम हूं।क्या इन दो वर्गों ने encapsulation का उल्लंघन किया है?

  1. क्या यह encapsulation सिद्धांत का उल्लंघन नहीं करता है?
  2. क्या यह एक विशिष्ट कारण है कि यह मानक में क्यों है?
  3. क्या इसका कोई उपयोग है, या यह नए मानक में बदला जा रहा है?
  4. क्या मानक में इस से संबंधित कोई खुले मुद्दे हैं?
+0

स्पष्ट करने के लिए - मेरे प्रश्न का उद्देश्य ब्रैकेट या encapsulation तोड़ने के मुश्किल तरीकों के बारे में बात नहीं करना था। मैं सिर्फ डिजाइन निर्णय या सी ++ की कुछ अन्य विशेषताओं पर चर्चा करना चाहता था जो इस सुविधा का कारण बन सकता है। क्या यह छिपाने की समस्या को हल करने के लिए समाधान का सिर्फ एक दुष्प्रभाव है या यह एक स्वतंत्र विशेषता है जिसे सी ++ में कुछ विशिष्ट कारण –

+0

के लिए पेश किया गया था। मुझे लगता है कि लोग इनकार करने के लिए इन सभी तरीकों को सूचीबद्ध कर रहे हैं, यह दस्तावेज नहीं है कि कैसे ऐसा करें, लेकिन यह बताने के लिए कि आपको encapsulation तोड़ना चुनना है। जब कोई त्रुटि होती है क्योंकि आपने किसी निजी विधि या सदस्य तक पहुंचने का प्रयास किया है, जो एक सभ्य अनुस्मारक के रूप में कार्य कर सकता है, और यदि आप डिजाइनर की इच्छाओं का सम्मान करते हैं, तो आप एक सहकारी समाधान तैयार करने के लिए नेतृत्व करते हैं। यह हमेशा दिया जाता है कि encapsulation जबरन टूटा जा सकता है। 'संरक्षित' encapsulation बल के बिना तोड़ा नहीं जा सकता है, जो मुझे नहीं लगता कि भाषा के हिस्से में विफलता है। –

उत्तर

12

हां ऐसा करता है और यही कारण है कि संरक्षित आलोचना का उचित हिस्सा प्राप्त हुआ है।

Bjarne Stroustrup, सी ++ के निर्माता, अपने उत्कृष्ट पुस्तक में इस पछतावा डिजाइन और सी के विकास ++:

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

+5

उन्होंने यह भी कहा कि उन्होंने सोचा था कि संरक्षित कार्य एक अच्छा विचार थे। यहां "समस्या" के उपयोग के बजाय "उपयोग" (जो मैं सुझाव दूंगा) का उपयोग है। –

+0

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

+2

@ मार्टिन, पुस्तक सुरक्षित संरक्षित कार्य कहती है: अच्छा, सुरक्षित डेटा: खराब। क्या आपने वास्तव में इसे पढ़ा है? –

18

आपने इसे स्वयं किया है।
आप लिखना

class Y : public X 
{ 
public: 
    void doA() 
    { 
     protectedFunction(); 
    } 
}; 

int main() 
{ 
    Y y1; 
    y1.doA(); 
} 

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

11

मुझे लगता है कि यह स्ट्रॉस्ट्रप खुद था, ने कहा कि सी ++ में निर्मित encapsulation और डेटा अखंडता सुविधाओं को ईमानदार लोगों को ईमानदार रखने के लिए, अपराधियों को रोकने के लिए डिज़ाइन किया गया है।

+4

मुझे इस प्रकार के प्रश्नों के लिए सी ++ एफएक्यू में कुछ जवाब पसंद हैं। 'मैं दूसरों से कैसे रोक सकता हूं ...' - एक टिप्पणी लिखकर, 'और मैं वास्तव में उन्हें कैसे करने से रोकता हूं ...' - एक टिप्पणी लिखें जिसमें कहा गया है कि अगर वे ऐसा करेंगे तो उन्हें निकाल दिया जाएगा। 'लेकिन अगर मैं वास्तव में, वास्तव में बाधा डालना चाहता हूं ...' - लड़के को आग लगाना। –

3

नहीं संरक्षित समारोह() संरक्षित है। आप इसे व्युत्पन्न कक्षाओं से कॉल करने के लिए स्वतंत्र हैं, इसलिए आप इसे सीधे वाई के सार्वजनिक सदस्य से बुला सकते थे, और इस सार्वजनिक सदस्य को मुख्य() से कॉल कर सकते हैं।

आप कर सकते थे अगर वह एक निजी विधि के साथ, वहाँ एक समस्या ... हो गया होता (थोड़ा साफ होने के लिए संपादित)।

+0

-1: प्रश्न में कोड संरक्षित विधि को व्युत्पन्न वर्ग के संदर्भ से कॉल नहीं करता है। संरक्षित विधि मुख्य() के दायरे से बुलाया जाता है। यदि आप 'उपयोग' घोषणाकर्ता को हटाते हैं, तो कोड अब संकलित नहीं होता है। –

+0

@ जॉन, यह स्पष्ट है! यह "ट्रामपोलिन" कार्य करने के बजाए सिर्फ एक शॉर्टकट है। यह बढ़ता नहीं है और न ही यह कार्य के संरक्षण स्तर को कम करता है। – Hexagon

+1

@ जॉन डिबलिंग: जिसका अर्थ है कि कार्यक्रम लेखक जानबूझकर समारोह को उजागर कर दिया। इसके बारे में एक सार्वजनिक रैपर समारोह को थप्पड़ मारना लगभग आसान होता। मुझे यहां एक डाउनवोट का कोई कारण नहीं दिख रहा है। –

1

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

संरक्षित कुछ सार्वजनिक घोषित करने का एक और जटिल तरीका है!

class Y : public X 
{ 
public: 
    void protectedFunction() { 
     X::protectedFunction(); 
    } 
}; 

एक बार एक विधि सुरक्षित है, यह पाने वर्गों के लिए की पेशकश की है:

+0

सार्वजनिक घोषित करने के लिए इसे संभव बनाने के तरीके की तरह, मैं कहूंगा। –

2

देखने की भाषा की दृष्टि से, कि व्युत्पन्न वस्तु में एक प्रतिनिधि विधि बनाने की तुलना में कैप्सूलीकरण के उल्लंघन के अधिक नहीं है जैसा चाहें उतना करने के लिए। using घोषणा का इरादा विरासत विधियों तक पहुंच नहीं बदल रहा था बल्कि विधि छिपाने के साथ समस्याओं से परहेज कर रहा था (जहां X में सार्वजनिक विधि Y में छिपी जाएगी यदि एक अलग अधिभार परिभाषित किया गया हो)।

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

यदि वास्तविक प्रश्न यह है कि क्या विशेष उपयोग एक डिजाइन बिंदु दृश्य से encapsulation का उल्लंघन है (जहां यहां डिजाइन डिज़ाइन है, भाषा डिज़ाइन नहीं है), तो शायद सबसे अधिक हां। वैसे ही आंतरिक डेटा या विधियों को सार्वजनिक रूप से बनाना। यह X की प्रारंभिक डिजाइनर द्वारा संरक्षित किया जाना डिजाइन किया गया था, तो संभावना है कि Y implementor यह सार्वजनिक होने के लिए नहीं करना चाहता था ... (या एक ही उद्देश्य के लिए एक delegating विधि की पेशकश कर रहे हैं)

+1

हाँ, अच्छी व्याख्या, पूरी तरह से सहमत हैं –

2

सं

सार्वजनिक विधि का उपयोग करने के लिए आप Y का एक उदाहरण यह काम नहीं करेगा होना चाहिए: अपनी नई परिभाषा Y एक नया इंटरफेस यह ऊपर वाई एक्स अभी भी सुरक्षित है को उजागर करता है, तो

int main() 
{ 
    X y1; 
    y1.protectedFunction(); 
} 

2

सी ++ में भी निजी संशोधक encapsulation की गारंटी नहीं देता है। कोई भी आपको अपने पैर में खुद को शूटिंग से रोक नहीं सकता है।

हर्ब सटर अपने लेख "Uses and Abuses of Access Rights" में विभिन्न तरीकों को demostrates कैसे आप "encapsulation तोड़ सकते हैं"।

हर्ब के आलेख से यहां मजाकिया उदाहरण।

ईविल मैक्रो जादू

#define protected public // illegal 
#include "X.h" 
//... 
X y1; 
y1.protectedFunction(); 
+1

यह अनिर्धारित व्यवहार है, आंशिक रूप से क्योंकि यह एक परिभाषा नियम को तोड़ देता है। यहां तक ​​कि यदि "संरक्षित" को फिर से परिभाषित करना कानूनी था, तो आप कक्षा के सदस्यों को उसी क्रम में नहीं मान सकते थे। –

+1

हां, मुझे अपरिभाषित व्यवहार के बारे में पता है। मैं यह दिखाना चाहता हूं कि यह चाल है, "ब्रेक encapsulatino", लेकिन संरक्षित नकली लपेटना नहीं है। –

1

नहीं, मैं वास्तव में समस्या नहीं दिख रहा।

के बजाय using, तो आप इस किया जा सकता है:

class X 
{ 
protected: 
    void protectedFunction() { cout << "i am protected" ; } 
}; 

class Y : public X 
{ 
public: 
    void protectedFunction() { X::protectedFunction(); } 
}; 

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

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

सदस्य को सुरक्षित बनाकर, आप व्युत्पन्न कक्षाओं को करने की स्वतंत्रता देते हैं, जिसे वे सदस्य के साथ पसंद करते हैं। वे इसे देख सकते हैं, इसलिए वे इसे संशोधित कर सकते हैं, या इसे सार्वजनिक रूप से बेनकाब कर सकते हैं। जब आप सदस्य को सुरक्षित करते हैं तो आपने इसे संभव बनाना चुना है। यदि आप इसे नहीं चाहते थे, तो आपको इसे निजी बनाना चाहिए था।

1

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

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

यदि आप संरक्षित विधि को सार्वजनिक करते हैं तो सुनिश्चित करें कि आप इस विशेष निर्णय के तर्क के बारे में समझाते हुए रखरखाव के लिए आंतरिक दस्तावेज़ीकरण प्रदान करते हैं।

सामान्य रूप से, पिछले योगदानकर्ता के रूप में सुरक्षा के लिए, आप शायद उप-वर्ग में एक प्रतिनिधि समारोह (एक अलग नाम के साथ) का उपयोग करना चाहते हैं। तो "get (int)" के बजाय आपके पास "getAtIndex (int)" या कुछ हो सकता है। यह आपको भविष्य में अधिक आसानी से रिफैक्टर/सुरक्षा/सार/दस्तावेज की अनुमति देता है।