2015-01-07 10 views
25
T& f() { // some code ... } 
const T& f() const { // some code ... } 

मैंने इसे दो बार देखा है (प्रारंभिक पुस्तक में मैं अब तक अध्ययन कर रहा हूं)। मुझे पता है कि पहला कॉन्स रिटर्न वैल्यू कॉन्स बनाता है, दूसरे शब्दों में: अपरिवर्तनीय। दूसरा कॉन्स यह अनुमति देता है कि समारोह को घोषित घोषित चर के लिए भी कहा जा सकता है, मुझे विश्वास है।कॉन्स और बिना के साथ समान कार्य - कब और क्यों?

लेकिन आप दोनों एक और एक ही कक्षा परिभाषा में क्यों कार्य करेंगे? और कंपाइलर इनके बीच अंतर कैसे करता है? मेरा मानना ​​है कि दूसरा एफ() (कॉन्स के साथ) गैर-कॉन्स वैरिएबल के लिए भी कहा जा सकता है।

+0

सुझाव: पहले एक आप को संशोधित करने की अनुमति देता है जो कुछ भी ' एफ() 'रिटर्न, जो वस्तु 'एफ()' का एक हिस्सा हो सकता है, पर कॉल किया जा रहा है। – juanchopanza

+2

द्वितीय श्रेणी को उस वर्ग की स्थिति को संशोधित करने की अनुमति नहीं है जिसे इस विधि में परिभाषित किया गया है। – kerem

+5

http://www.parashift.com/c++-faq/const-overloading.html –

उत्तर

21

लेकिन तुम क्यों एक और एक ही वर्ग परिभाषा की दोनों कार्यों के लिए होता है?

दोनों रखने से आपको अनुमति देता है:

  • कॉल एक परिवर्तनशील वस्तु पर समारोह, और यदि आप चाहें तो परिणाम को संशोधित; और
  • फ़ंक्शन को const ऑब्जेक्ट पर कॉल करें, और केवल परिणाम देखें।

केवल पहले के साथ, आप इसे const ऑब्जेक्ट पर कॉल नहीं कर सके। केवल दूसरे के साथ, आप उस ऑब्जेक्ट को संशोधित करने के लिए इसका उपयोग नहीं कर सकते जिस पर यह संदर्भ देता है।

और कंपाइलर इनके बीच अंतर कैसे करता है?

यह const अधिभार चुनता समारोह पर एक const वस्तु (या एक संदर्भ या const सूचक के माध्यम से) कहा जाता है। यह अन्य अधिभार अन्यथा चुनता है।

मेरा मानना ​​है कि दूसरा एफ() (कॉन्स के साथ) गैर-कॉन्स्ट चर के लिए भी कहा जा सकता है।

यदि यह एकमात्र ओवरलोड था, तो यह हो सकता था। दोनों ओवरलोड के साथ, गैर-const ओवरलोड का चयन इसके बजाय किया जाएगा। जबकि अभी भी गैर स्थिरांक उदाहरणों डेटा को संशोधित करने में सक्षम होने

5

कोई भी कॉन्स्ट्रेंस वाला पहला व्यक्ति कॉलर को ऑब्जेक्ट को संशोधित करने की अनुमति देता है, जो सामान्य रूप से कक्षा के सदस्य हैं जिनकी विधि कहलाती है।

दूसरा, जहां हमारी मेजबान कक्षा केवल-पढ़ने योग्य मोड में है, बल्कि इसके सदस्य को केवल पढ़ने के लिए अनुमति देता है।

डिफ़ॉल्ट रूप से, गैर-कॉन्स संस्करण को लागू किया जाता है यदि इसे स्थिरता के नियमों के तहत अनुमति दी जाती है।

इसका सबसे आम उदाहरण किसी प्रकार के संग्रह/सरणी प्रकार वर्ग के साथ है।

class Array 
{ 
    private: 
     MyType members[MySize]; 

    public: 
     MyType & operator[](size_t index); 
     const MyType & operator[](size_t index) const; 
}; 

मान लें कि वे लागू किए गए हैं और यह एक टेम्पलेट हो सकता है या वे ठोस प्रकार और आकार हैं। मैं कॉन्स अधिभार का प्रदर्शन कर रहा हूँ।

अब हम कक्षा का उपयोग कर किसी के पास हो सकते हैं। आप एक मूल्य निर्धारित करना चाहते हो सकता है।

Array myArray; 
myArray[ 3 ] = myObject; 

या आप केवल इसे पढ़ने हो सकता है:

const Array& myArrayRef = getArrayRef(); // gets it to read 
const MyType & myValueRef = myArrayRef[ 3 ]; 

तो तुम दोनों एक मूल्य निर्धारित करने के लिए मैं संकेतन का उपयोग और एक पढ़ सकते हैं देखते हैं। operator[] के साथ, आप इस तकनीक को किसी भी विधि पर लागू कर सकते हैं।

12

लेकिन आप दोनों एक ही कक्षा परिभाषा में क्यों कार्य करेंगे?

कभी-कभी आप const ऑब्जेक्ट या non-const ऑब्जेक्ट पर इसे लागू किए जाने के आधार पर एक ही ऑपरेशन के लिए अलग-अलग अर्थशास्त्र प्रदान करना चाहते हैं। के std::string वर्ग की एक उदाहरण लेते हैं: -

char& operator[](int index); 
const char& operator[](int index) const; 

इस मामले में जब operator[]const वस्तु आप नहीं दूँगी स्ट्रिंग की सामग्री को बदलने के लिए उपयोगकर्ता के माध्यम से लागू किया।

const std::string str("Hello"); 
str[1] = 'A';  // You don't want this for const. 

दूसरी तरफ, गैर-कॉन्स स्ट्रिंग के मामले में आप उपयोगकर्ता को स्ट्रिंग की सामग्री को बदलने देते हैं। यही कारण है कि एक अलग अधिभार।

और कंपाइलर इनके बीच अंतर कैसे करता है?

संकलक जांच करता है कि विधि const वस्तु या non-const वस्तु पर शुरू हो जाती है और उसके बाद उचित रूप से है कि विधि कॉल या नहीं।

const std::string str("Hello"); 
cout << str[1];   // Invokes `const` version. 

std::string str("Hello"); 
cout << str[1];   // Invokes non-const version. 
3

यह दोनों के लिए आप की अनुमति देता है, एक केवल पढ़ने के लिए रास्ते में स्थिरांक उदाहरणों डेटा की पहुंच है।

एक सदस्य समारोह void Foo::bar() तरह इस तरह है:: void bar(Foo *this)

#include <iostream> 

class test 
{ 
    public: 
    test() : data_(0) {} 

    int& f() { return data_; } 
    const int& f() const { return data_ } 

    private: 
    int data_; 
}; 

int main(void) 
{ 
    const test rock; 
    test paper; 

    /* we can print both */ 
    std::cout << rock.f() << std::endl; 
    std::cout << paper.f() << std::endl; 

    /* but we can modify only the non const one */ 
    // rock.f() = 21; 
    paper.f() = 42; 

} 
4

समारोह कॉल कोष्ठक के बाद क्वालीफायर सदस्य कार्यों में से छिपा this पैरामीटर के लिए लागू होते हैं। लेकिन क्या होता है यदि फू ऑब्जेक्ट const है?

struct Foo { 
    void bar(); 
}; 

const Foo f{}; 
f.bar(); 

ठीक है, के बाद से Foo::bar() एक Foo *this पैरामीटर, जो const होने की अनुमति नहीं है लेता है, इसके बाद के संस्करण f.bar(); संकलित करने के लिए विफल रहता है। तो हमें छिपे हुए this पैरामीटर को अर्हता प्राप्त करने के लिए एक तरीका चाहिए, और जिस तरह से सी ++ ऐसा करने का विकल्प चुनता है वह उन क्वालीफायरों को फ़ंक्शन पैरों के बाहर जाने की अनुमति देता है।

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

इसके अलावा, const एकमात्र क्वालीफायर नहीं है। आप volatile क्वालीफायर भी जोड़ सकते हैं, और सी ++ 11 में आप लवल्यू और रावल्यू रेफरेंस क्वालीफायर भी डाल सकते हैं।


कारण है कि हम इस समारोह के दो लगभग समान प्रतियां की जरूरत है एक ही अंतर बाहर निकलने के लिए कोई सीधा रास्ता नहीं है क्योंकि वहाँ है: विभिन्न वापसी प्रकार के। यदि हमारे पास एक कॉन्स ऑब्जेक्ट है, और उस ऑब्जेक्ट में एक गेटटर है जो इसमें शामिल किसी संदर्भ का संदर्भ देता है, तो उस संदर्भ को समग्र ऑब्जेक्ट के समान योग्यता प्राप्त करने की आवश्यकता होती है।

struct Foo { 
    int i; 
    int &get_i() const { return i; } 
}; 

int main() { 
    const Foo f{}; 
    f.get_i() = 10; // i should be const! 
} 

ऊपर भी संकलन नहीं होगा Foo::get_i() const क्योंकि अंदर, i स्थिरांक है, और हम यह करने के लिए एक गैर स्थिरांक संदर्भ नहीं लौट सकते। लेकिन अगर इसकी अनुमति थी, तो यह गलत होगा क्योंकि हमें किसी कॉन्स ऑब्जेक्ट के सदस्यों को संशोधित करने में सक्षम नहीं होना चाहिए। तो Foo::get_i() const को i पर एक कॉन्स्ट संदर्भ वापस करने की आवश्यकता है।

int const &Foo::get_i() const { return i; } 

लेकिन हम एक गैर स्थिरांक वस्तु के एक सदस्य को संशोधित करने में सक्षम होना चाहिए,

int main() { 
    Foo f{}; 
    f.get_i() = 10; // should be fine 
} 

इसलिए हम केवल इस समारोह नहीं हो सकता। हमें एक फ़ंक्शन की आवश्यकता होती है जो एक गैर-कॉन्स्ट संदर्भ देता है जब फू ऑब्जेक्ट स्वयं नहीं होता है। तो हम वस्तु का स्थिरांक सत्ता के आधार पर समारोह को ओवरलोड:

struct Foo { 
    int i; 
    int const &get_i() const { return i; } 

    int &get_i() { return const_cast<int &>(const_cast<Foo const *>(this)->get_i()); } 
}; 

है यही कारण है कि, गैर:

struct Foo { 
    int i; 
    int const &get_i() const { return i; } 
    int &get_i() { return i; } 
}; 

तो समारोह शरीर अधिक वहाँ एक संभव है कि दोहराव से बचने के विकल्प को मुश्किल है -कॉन्स्ट ओवरलोड प्रकार को ठीक करने के लिए const_cast का उपयोग करके, कॉन्स ओवरलोड पर इसके कार्यान्वयन को प्रतिनिधि करता है। कॉन्स जोड़ना हमेशा सुरक्षित है। एक const_cast का उपयोग कर कॉन्स्ट को हटाने केवल तभी सुरक्षित होता है जब हम यह सुनिश्चित करने के लिए जानते हैं कि मूल वस्तु नहीं है। हम जानते हैं कि इस मामले में, क्योंकि हम जानते हैं कि हमने पहले स्थान पर नॉन-कॉन्स्ट ऑब्जेक्ट में कॉन्स जोड़ा था।

4

क्यूटी ढांचे में एक बहुत अच्छा उदाहरण है।

QImage कक्षा पर एक नज़र डालें।

const uchar* scanLine (int i) const; 
uchar* scanLine (int i); 

पहले एक पढ़ने के लिए पहुंच के लिए है:

दो सार्वजनिक समारोहों रहे हैं। दूसरा यह मामला है कि आप स्कैन लाइन को संशोधित करना चाहते हैं।

यह भेद महत्वपूर्ण क्यों है? क्योंकि क्यूटी implicit data sharing का उपयोग करता है। इसका मतलब यह है, QImage तुरंत एक गहरी प्रतिलिपि प्रदर्शन नहीं करता है, तो आप कुछ इस तरह करते हैं:

QImage i1, i2; 
i1.load("image.bmp"); 
i2 = i1;      // i1 and i2 share data 

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

3

जैसा कि पहले उल्लेख किया गया था, आप const और गैर-const इनवॉकिंग ऑब्जेक्ट की कॉन्स्ट-नेस के आधार पर कार्यों के संस्करणों का उपयोग कर सकते हैं। प्रतिमान अक्सर operator[] के साथ सरणी के लिए प्रयोग किया जाता है।एक तरह से कोड दोहराव (स्कॉट Meyers 'पुस्तक प्रभावी सी ++ से लिया गया) से बचने के लिए const_cast जैसे एक गैर स्थिरांक अधिभार में const समारोह वापसी, के लिए है:

// returns the position of some internal char array in a class Foo 
const char& Foo::operator[](std::size_t position) const 
{ 
    return arr[position]; // getter 
} 

// we now define the non-const in terms of the const version 
char& Foo::operator[](std::size_t position) 
{ 
    return const_cast<char&>(// cast back to non-const 
     static_cast<const Foo&>(*this)[position] // calls const overload 
    ); // getter/setter 
} 
संबंधित मुद्दे