2010-02-16 13 views
18

मैं सी ++ में private एक्सेस विनिर्देशक की वैधता का प्रयास कर रहा था। यहाँ जाता है:सी ++ निजी वास्तव में निजी है?

इंटरफ़ेस:

// class_A.h 

class A 
{ 
public: 
    void printX(); 
private: 
    void actualPrintX(); 
    int x; 
}; 

कार्यान्वयन:

// class_A.cpp 
void A::printX() 
{ 
    actualPrintX(); 
} 

void A::actualPrintX() 
{ 
    std::cout << x: 
} 

मैं यह एक स्थिर पुस्तकालय (ए/उदारीकरण) करने के लिए बनाया। अब हमारे पास class_A.h और classA.a (या classA.lib) जोड़ी है। मैंने class_A.h संपादित किया और इससे private: हटा दिया।

अब

एक और classTester.cpp में:

#include "class_A.h" // the newly edited header 

int main() 
{ 
    A a; 

    a.x = 12;   // both G++ and VC++ allowed this! 
    a.printX();   // allowed, as expected 
    a.actualPrintX(); // allowed by G++, VC++ gave a unresolved linker error 

    return 0; 
} 

मुझे पता है कि एक पुस्तकालय के हेडर छेड़छाड़ के बाद सभी दांव बंद कर रहे हैं (मेरा मतलब है, प्रणाली अखंडता, आदि) विधि यद्यपि hacky जा रहा है, यह वास्तव में है अनुमति? क्या इसे अवरुद्ध करने का कोई तरीका है? या मैं यहाँ कुछ गलत कर रहा हूँ?

+0

मुझे पता है कि चेशर बिल्ली (पिंपल - निजी इम्प्लायर http://en.wikipedia.org/wiki/Cheshire_Cat_Idiom_%28programming_technique%29) डिज़ाइन यहां संभव है और यह भी कि एक्सेस विनिर्देशक संकलक द्वारा संकलित-समय गार्ड हैं । – legends2k

+0

पृथ्वी पर क्यों आप इसे पुनर्निर्माण नहीं कर सकते? –

+0

@ डोमिनिक: मेरा इरादा यह देखना था कि क्या होता है यदि मैं कक्षा के निजी हिस्सों तक पहुंचने की कोशिश कर रहा हूं। – legends2k

उत्तर

30

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

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

7

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

2

कोई ए :: वास्तविकप्रिंटएक्स कार्यान्वयन कहीं भी नहीं है। वह आपकी लिंकर त्रुटि है।

+0

अधिसूचना के लिए धन्यवाद, यह एक टाइपो है, मैंने इसे अभी ठीक कर दिया है :) – legends2k

+0

दोस्तों, कृपया उसे वोट न दें। इससे पहले सवाल में, मैंने केवल 'ए :: वास्तविकप्रिंटएक्स() 'के बजाय' वास्तविकप्रिंटएक्स() 'रखा है; उसने मुझे उस टाइपो के बारे में अधिसूचित किया। – legends2k

9

आप सी ++ में क्या अनुमति है उससे परे भटक गए हैं, तो आप जो कर रहे हैं उसे अनुमति नहीं है - लेकिन निश्चित रूप से यह कुछ परिस्थितियों में कुछ कंपाइलरों पर काम कर सकता है।

विशेष रूप से, आप One Definition Rule का उल्लंघन कर रहे हैं।

यह article हर्ब सटर द्वारा इसे काफी अच्छी तरह से समझाता है - यह एक्सेस विनिर्देशक प्रणाली को बाधित करने का एक कानूनी और पोर्टेबल तरीका भी प्रदान करता है।

+0

लेकिन मैंने एक से अधिक बार परिभाषित नहीं किया है; सहमत हैं, मैंने घोषणा को छेड़छाड़ की है, लेकिन यह ओडीआर उल्लंघन का मामला कैसे बनता है? – legends2k

+2

आपने 'कक्षा ए' को दो बार परिभाषित किया है - एक बार' classTester.cpp' अनुवाद इकाई में और एक बार 'class_A.cpp' अनुवाद इकाई में। ओडीआर उल्लंघन यह है कि उन दो परिभाषाएं इंडेंटिकल नहीं हैं। –

+0

आर्ग, मैं इसे अब देखता हूं! उसी पर सटर के लेख के लिए धन्यवाद। – legends2k

5

मैंने कोशिश की। यह एक कार्यक्रम का एक एनएम है जिसे मैंने एक निजी विधि और एक सार्वजनिक के साथ कक्षा परीक्षण किया था।

0000000100000dcc T __ZN4Test3barEv 
0000000100000daa T __ZN4Test3fooEv 

जैसा कि आप देख सकते हैं, हस्ताक्षर बिल्कुल वही है। लिंकर के पास सार्वजनिक विधि से निजी विधि को अलग करने के लिए बिल्कुल कुछ नहीं है।

+0

हां, जैसा कि मैंने उल्लेख किया है, जी ++ में 'actualPrintX()' तक पहुंचने के लिए बिल्कुल कोई त्रुटि नहीं थी; लेकिन वीसी ++ में प्रतीकों में कुछ अंतर होता है और इसलिए लिंकर ने एक त्रुटि फेंक दी। धन्यवाद! – legends2k

5

मैं अन्य उत्तरों के साथ सहमत हूं।

हालांकि, मैं कहना है कि यह एक संकलक के लिए पूरी तरह से स्वीकार्य है शारीरिक रूप से सदस्यों को अलग ढंग से व्यवस्था करने के लिए जब आप उस private को दूर करना चाहते हैं। अगर यह काम करता है, तो वह भाग्य है। आप इस पर भरोसा नहीं कर सकते हैं। यदि दोनों पक्ष एक ही घोषणा का उपयोग नहीं कर रहे हैं, तो वे वास्तव में एक ही कक्षा का उपयोग नहीं कर रहे हैं।

2

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

नोट: आपको इस उदाहरण में आंतरिक वस्तु को आवंटित/मुक्त करने का ट्रैक रखना होगा। ऐसा करने के अन्य तरीके हैं जिन्हें इसकी आवश्यकता नहीं है।

// class_A.h 
class A { 
public: 
    void printX(); 
private: 
    void *Private; 
}; 

// class_A.cpp 
class A_private { 
    void actualPrintX(); 
    int x; 
}; 

void A::printX() { 
    reinterpret_cast<A_private *>(Private)->actualPrintX(); 
} 

void A_private::actualPrintX() { 
    std::cout << x: 
} 
+0

इसी प्रकार, प्रश्न के बगल में, टिप्पणियों में, मैंने चेशर बिल्ली विधि के बारे में भी उल्लेख किया है, जो इसके समान है, केवल reinterpret_cast के बिना। – legends2k

+0

मुझे माफ़ कर दो, मुझे यह याद आना चाहिए; यह जानना अच्छा है कि वास्तव में इसका नाम है। – Ioan

1

ज्यादातर मामलों में आप भी निजी सदस्यों को सार्वजनिक करने का हेडर फाइल को संपादित करने की जरूरत नहीं है। आप प्रीप्रोसेसर के साथ ऐसा कर सकते हैं। कुछ इस तरह:

//"classWithPrivateMembers.hpp" 
class C 
{ 
private: //this is crucial for this method to work 
    static int m; 
}; 

int C::m = 12; 

और फिर, इस काम करेगा:

#define private public 
#include "classWithPrivateMembers.hpp" 
#undef private 

int main() 
{ 
    C::m = 34; // it works! 
} 
+0

आप अयोग्य निजी वार्स को पकड़ने के लिए '# डिफाईन क्लास स्ट्रक्चर 'भी जोड़ सकते हैं। – mskfisher

1

याद रखिए भी है कि जब आप एक सदस्य चर का उपयोग कर सकते बदलने के लिए, संकलक यह एक अलग वर्ग के भीतर ऑफसेट पर जगह हो सकती है वस्तु। मानक कंपाइलरों को पुनर्व्यवस्थित करने में कम से कम स्वतंत्रता की अनुमति देता है (कम से कम उसी पहुंच स्तर के भीतर, मुझे लगता है)।