2011-01-29 18 views
24

सी ++ में hiding rule के पीछे तर्क क्या है?सी ++: छिपाने के नियम के पीछे तर्क

class A { void f(int); } 
class B : public A { void f(double); } // B::f(int) is hidden 
  • यदि यह एक सार्थक सुविधा मुझे लगता है कि यह भी एक ही नाम के साथ नए कार्यों को परिभाषित करने के बिना कार्यों को छिपाने के लिए संभव हो जाना चाहिए है: कुछ इस तरह:

    class B : public A { hide void f(double); } 
    

    लेकिन यह नहीं है मुमकिन।

  • मैं इसे compilers काम सरल नहीं लगता कि, के बाद से compilers वैसे भी प्रकट करें कार्यों में सक्षम होना चाहिए जब आप स्पष्ट रूप से using निर्देश का उपयोग करें:

    class B : public A { using A::f; void f(double); } // B::f(int) NOT hidden 
    

तो, कैसे आना है एक छुपा नियम?


हम, सभी तीन उत्तरों अच्छे लगते हैं, और छुपा नियम के लिए अलग तर्कसंगत दिखाते हैं। मुझे यकीन नहीं है कि मुझे किस उत्तर को स्वीकार करना चाहिए।

+0

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

+0

AFAIK, * नए कार्यों को परिभाषित किए बिना छुपा * * + delete' के माध्यम से C++ 11 में संभव है। – Walter

+0

बेस क्लास कार्यों को छिपाने के लिए _is_ एक तंत्र है। 'कक्षा ए' के ​​बजाय 'कक्षा ए: संरक्षित बी {...};' का उपयोग करें। एक मृत घोड़े को मारने के लिए खेद है। –

उत्तर

10

यह एक बालों का सवाल है, लेकिन स्पष्ट रूप से विचार यह है कि यह छिपाने की सुविधा बेस क्लास में परिवर्तन करते समय सूक्ष्म बग से बचने में मदद करती है (जो अन्यथा "चोरी" कर सकती है जो पहले व्युत्पन्न कक्षा द्वारा संभाली जाती थी)। फिर भी बेस क्लास में बदलाव व्युत्पन्न कक्षाओं के संकलन के परिणाम को प्रभावित कर सकता है, इसलिए मुझे नहीं लगता कि मैं इस स्पष्टीकरण को 100% समझता हूं।

मैं मानता हूं कि इस विषय पर अक्सर चर्चा की जाती है कि शायद छिपाने से वास्तव में सी ++ प्रोग्रामर में "आश्चर्य" की मात्रा बढ़ जाती है।

इस मुद्दे के बारे एक विस्तृत चर्चा here पाया जा सकता है ...

9

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

छिपाने से आपको कुछ तरीकों से मदद मिलती है।

आधार वर्ग के लिए एक विधि जोड़ना डिफ़ॉल्ट रूप से व्युत्पन्न वर्ग के लिए ओवरलोड रिज़ॉल्यूशन को प्रभावित नहीं करेगा।

और आप औपचारिक तर्क void* के साथ बेस क्लास विधि के लिए तर्क false कहने के साथ अपने कॉल को निर्देशित करने वाले कुछ दुर्घटनाओं से अधिभार संकल्प को दूर नहीं करते हैं। ऐसी बातें। ।

चियर्स & hth,

+0

मैं परेशान हूं कि आप वास्तव में अकेले हैं जिन्होंने दूसरों के दायरे से छिपाने के कार्यों के साथ स्थिरता के बारे में बात की! मुझे अभी भी लगता है कि यह ज्यादातर आश्चर्य से बचने का मामला है। –

7

मुझे यकीन है कि मैं इस मामले एक सी द्वारा की पेशकश देखा है हूँ ++ अहम शख्स, यकीन नहीं जो:

struct Base { 
    void f(const Base&); 
}; 

struct Derived : Base { 
    using Base::f; 
    void f(double); 
}; 

int main() { 
    Derived d; 
    d.f('a'); // calls Derived::f 
} 

अब, Base करने के लिए void f(int); जोड़ने के लिए, और अर्थ मुख्य परिवर्तनों में - यह Base::f पर कॉल करता है क्योंकि intchar के लिए एक बेहतर मिलान है - यह एक मानक रूपांतरण के बजाय एक पूर्णांक पदोन्नति है।

यह स्पष्ट नहीं है कि आधार के लिए कि परिवर्तन वास्तव में प्रोग्रामर द्वारा इरादा char के साथ कॉल को पकड़ने के लिए है, तो मतलब है using डिफ़ॉल्ट व्यवहार है कि परिवर्तन बुला कोड को प्रभावित नहीं करता है की आवश्यकता होती है में स्पष्ट होना होगा नहीं है। मेरा मानना ​​है कि यह एक मामूली कॉल है, लेकिन मुझे लगता है कि समिति ने फैसला किया है कि सी ++ में बेस क्लास उतने ही नाजुक थे जितना वे हैं :-)

"छुपाएं" कीवर्ड की कोई आवश्यकता नहीं है क्योंकि इसके लिए कोई तुलनात्मक मामला नहीं है बेस से छिपाने "एफ" जब व्युत्पन्न में अधिभारित नहीं है।

बीटीडब्ल्यू, मैंने प्रकारों को चुना है, और char जानबूझकर असंगत है। int बनाम char के बजाय int बनाम unsigned int के साथ आप अधिक सूक्ष्म मामले प्राप्त कर सकते हैं।

-2

शायद, कारण टेम्पलेट विशेषज्ञता है।

template <int D> struct A { void f() }; 

template <> struct A<1> { void f(int) }; 

template <int D> 
struct B: A<D> 
{ 
    void g() { this->f(); } 
}; 

टेम्पलेट वर्ग बी एक विधि f() है, लेकिन जब तक आप वर्ग बी का एक उदाहरण नहीं बनाते आप हस्ताक्षर नहीं जानता: मैं आपको एक उदाहरण देता। तो कॉल this->f() किसी भी समय "कानूनी" है। जब तक आप उदाहरण बनाते हैं, तब तक जीसीसी और सीएलएंग दोनों त्रुटि की रिपोर्ट नहीं करते हैं। लेकिन जब आप B<1> उदाहरण पर g() विधि को कॉल करते हैं तो वे त्रुटि इंगित करते हैं। तो छुपा नियम यह जांचने के लिए आसान रहता है कि आपका कोड मान्य है या नहीं।

मैं अपने उदाहरण में उपयोग किए गए कोड के अंतिम भाग की रिपोर्ट करता हूं।

int main (int argc, char const *argv[]) 
{ 
    B<0> b0; /* valid */ 
    B<1> b1; /* valid */ 

    b0.g(); /* valid */ 
    b1.g(); /* error: no matching function for call to ‘B<1>::f()’ */ 

    return 0; 
} 
+3

इसके अलावा, आपके उदाहरण में, टेम्पलेट क्लास बी में बिल्कुल कुछ भी नहीं है जो टेम्पलेट क्लास ए में घोषित विधि f को छुपाएगा ... त्रुटि इस तथ्य से नहीं आती है कि बी (शून्य) बी <1> में छिपा हुआ है (बी <0> की तुलना में बी <1> में यह और अधिक छुपा क्यों होगा क्योंकि कोई विशेषज्ञता नहीं है)।आपकी समस्या * बस * है कि एफ (शून्य) ए <1> में बिल्कुल घोषित नहीं किया गया है: छिपाने के लिए कुछ भी नहीं है। –

3

आधार वर्ग के सदस्य समारोह छुपा (एक ही नाम पर अलग हस्ताक्षर के साथ) के लिए एक अन्य कारण वैकल्पिक पैरामीटर की वजह से अस्पष्टता की वजह से हो सकता है।

#include <stdio.h> 

class A 
{ 
public: 
    int foo(int a, int b=0) 
    { 
     printf("in A : %d, %d\n", a, b); 
    } 
}; 

class B : public A 
{ 
public: 
    int foo(int a) 
    { 
     printf("in B : %d\n", a); 
     foo(a); //B:foo(a) will be called unless we explicitly call A:foo(a) 
     foo(a, 1); // compile error: no matching function for call to B:foo(int&, int) 
    } 
}; 


int main() 
{ 
    B b; 
    b.foo(10); 
    return 0; 
} 

आधार वर्ग में foo प्रक्रिया गुप्त रखी नहीं बन गया था, तो यह संभव नहीं है क्योंकि निम्न पंक्ति दोनों हस्ताक्षर से मेल खाता है संकलक B::foo तय करने के लिए कि क्या A::foo बुलाया जाना चाहिए या होगा: निम्न उदाहरण पर विचार करें:

foo(a); 
संबंधित मुद्दे