2012-10-17 14 views
5

संभव डुप्लिकेट:
Operator overloading"<<" and ">>" ऑपरेटर I/O कैसे करते हैं?

मैं सेल्सियस तक ++ एक लंबे समय से प्रतीक्षा में वापसी कर रहा हूँ और वहाँ कुछ बुनियादी अंकन है कि वास्तव में नहीं है कि अन्य भाषाओं में प्रमुख होने लगते हैं।

आप कोड

cout << "firstvalue is " << firstvalue << endl; 

की इस पंक्ति को देखें, तो मैं क्या करता है एहसास। यह कंसोल के लिए "firstvalue x है" लिखते हैं। एक्स पहली बार मूल्य का मूल्य है। हालांकि, मुझे "< <" या ">>" डबल एंग्लेड ब्रैकेट के बारे में कुछ भी पता नहीं है। मैं उनको शोध करने में सक्षम नहीं हूं या वे क्या करते हैं क्योंकि मुझे उनके लिए औपचारिक नाम नहीं पता है।

मेरा प्रश्न है, वास्तव में उपरोक्त कथन में (चरण-दर-चरण) होता है? और ये "< <" के लिए क्या हैं? मुझे लगता है कि मैं समझता हूं कि कंसोल को लिखने के लिए cout एक मानक लाइब्रेरी फ़ंक्शन है। हालांकि मैं या तो उद्देश्य-सी या डॉट नोटेशन के लिए प्रयोग किया जाता है। मुझे नहीं लगता कि यह "cout" फ़ंक्शन किस सदस्य का सदस्य है।

मैं printf को थोड़ा और आसानी से समझ सकता हूं, कम से कम यह तर्कों के लिए ब्रेसिज़ प्रदान करता है। जैसे printf ("यहां आपकी स्ट्रिंग")।

+2

अनिवार्य पढ़ने: [परिभाषित सी ++ पुस्तक गाइड और सूची] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) –

+1

इस संदर्भ में, << 'एक [ऑपरेटर] (http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt) है और अभिव्यक्ति उस ऑपरेटर को कॉल के परिणामों को चेन कर रही है। – juanchopanza

+2

'cout' एक समारोह नहीं है। यह एक वस्तु है, जिसके लिए '<<' ऑपरेटर अधिभारित है। – Grizzly

उत्तर

13

सी ++ ऑपरेटर ओवरलोडिंग की अनुमति देता है। इसका मतलब है कि उपयोगकर्ता द्वारा परिभाषित प्रकार अंतर्निहित ऑपरेटरों पर अपने व्यवहार को परिभाषित कर सकता है। इस मामले में ऑपरेटरों को कहा जाता है: left shift या right shift ऑपरेटर। उन ऑपरेटरों को परंपरागत रूप से बिट-स्थानांतरण के लिए इस्तेमाल किया गया है, लेकिन मानक पुस्तकालय उन्हें स्ट्रीमिंग परिचालनों का प्रतीक बनाने के लिए दोहराता है।

आप C and C++ here में उपलब्ध ऑपरेटरों की एक सूची पा सकते हैं।

अपने मामले में आप एक स्ट्रिंग अक्षरशः और std::cout में किसी प्रकार का मान स्ट्रीम कर रहे हैं, जो std::basic_ostream प्रकार का एक ऑब्जेक्ट है।

चरण-दर-चरण

पूर्वता नियमों के बाद अपने कोड इस तरह दिखता है लागू किया गया है:

((cout << "foobar") << x) << endl; 

संकलक मूल रूप से object << object भाव फ़ंक्शन कॉल में बदलना होगा।

operator<<(operator<<(operator<<(cout, "foobar"), x), endl); 

फिर यह पता लगाएगा कि कौन से अधिभार को कॉल करना है। (यह वास्तव में मुश्किल है। अभी यह विश्वास करने के लिए पर्याप्त होना चाहिए कि यह तर्क मिलान के साथ operator<< का ओवरलोड लोड करता है)।

मूल_स्ट्रीम के लिए अंतर्निहित अधिकांश ओवरलोड here और here हैं।(istream >> के मामले में या निकासी,)

// Let the function 'print' be a renaming of 'operator<<' 
// with T being the type of the object you want to print. 
std::ostream& print(std::ostream&, const T&); 

// 1) Print "first value is" and then return the stream you 
// to which to just printed (ie. cout). 2) Use the returned 
// stream to chain function calls and print 'firstValue'. 
print(print(std::cout, "first value is"), firstValue); 
+0

स्ट्रिंग अक्षर लेने वाला अधिभार वास्तव में एक सदस्य नहीं है, यह मेरे द्वारा लिंक किए गए नि: शुल्क कार्यों में से एक है। –

+0

धन्यवाद, मुझे पहले यह समझ में नहीं आया, तो मैंने त्वरित सी ++ पढ़ने के लिए कुछ समय लगाया। और इसे फिर से पढ़ने के बाद, यह सब अधिक समझ में आया। –

1

यह निम्न के लिए वाक्यात्मक चीनी है -शिफ्ट ऑपरेटर।

तो, यह:

int x = 1 << 1; 

थोड़ा बदलाव है, लेकिन इस:

std::cout << x; 

एक धारा प्रविष्टि है। आप इसे स्पष्ट रूप से लिख सकते हैं:

operator <<(std::cout, x); 

और बिल्कुल वही परिणाम प्राप्त करें। (वे उपयोगकर्ता परिभाषित प्रकार के लिए अतिभारित किया जा सकता है, इसलिए यह अपने खुद के लिखने के लिए असामान्य नहीं है) धारा प्रविष्टि ऑपरेटरों के पारंपरिक प्रारूप

std::ostream& operator <<(std::ostream&, T value); 

है (संदर्भ) के द्वारा उत्पादन धारा दिया जाता है ताकि आप श्रृंखला कॉल कर सकते हैं: अपने उदाहरण तब्दील हो के रूप में:

operator<< (
    operator<< (
    operator<<(std::cout, "firstvalue"), 
    firstvalue 
), 
    std::endl 
); 

ओह, और ... std::cout (और std::cerr आदि) कार्यों नहीं हैं: वे वैश्विक वस्तुओं रहे हैं। यहां पर कार्य ओवरलोडेड << ऑपरेटर है। उनके बारे में FILE *stdout, *stderr समकक्षों के बारे में सोचें।

printf एट पर सी ++ iostreams के कुछ फायदे हैं। अल:

  • प्रकार-सुरक्षा: आप गलती से "%f" साथ एक पूर्णांक मुद्रित नहीं कर सकते और कचरा मिलता है, अधिभार संकल्प स्वचालित रूप से संकलन समय पर std::ostream& operator<<(std::ostream&, double) समारोह का चयन करता है, क्योंकि उपयोगकर्ता परिभाषित प्रकार के लिए
  • समर्थन: आप लिख सकते हैं आपके whizzy नई कक्षा के लिए एक स्ट्रीम सम्मिलन ऑपरेटर, और यह बस काम करेगा, हर जगह
  • स्ट्रीम अबास्ट्रक्शन: आप स्टडआउट और stderr (cout/cerr) को प्रारूपित करने के लिए उसी ओवरलोड (इसलिए आप उन्हें केवल एक बार लिख सकते हैं) का उपयोग कर सकते हैं, और फ़ाइलें (std::ofstream) और स्ट्रिंग्स (std::ostringstream)। printf/fprintf/snprintf को अलग से संभालने की कोई आवश्यकता नहीं है।

भी कुछ नुकसान कर रहे हैं:

  • प्रदर्शन: सभी कि अमूर्त के लिए कुछ दंड, और स्थान प्रणाली की व्यापकता जो क्रम
  • शब्दाडंबर पर कॉन्फ़िगर किया गया है: कम से कम आदिम के लिए पहले से ही printf द्वारा समर्थित प्रकार, प्रारूप तार बहुत terser और अधिक अर्थपूर्ण हैं
2

वे धारा प्रविष्टि के रूप में भेजा रहे हैं, और वास्तव में बाएं पारी और अधिकार का अर्थ अधिभार हैं:

4

<< ऑपरेटर "अंकगणित छोड़ बदलाव" में सी + है +।उदाहरण के लिए:

3 << 2 

का मूल्यांकन करता है 12. करने के लिए कारण यह है कि 3 की बाइनरी प्रतिनिधित्व

00000011 

छोड़ दिया आप प्राप्त

00001100 

और संख्यात्मक मान के लिए दो बार यह स्थानांतरण है परिणाम 12 है।

आउटपुट के साथ इसे क्या करना है? वास्तव में कुछ भी नहीं। हालांकि सी ++ में आप ओवरलोडिंग के लिए ऑपरेटर के अर्थ को फिर से परिभाषित कर सकते हैं। सी ++ मानक लाइब्रेरी ने बाएं-शिफ्ट ऑपरेटर के अर्थ को "प्रेषण-स्ट्रीम" के प्रकार के रूप में परिभाषित करने का निर्णय लिया।

तो क्या होता है कि मूल्य std::cout रूप

std::cout << "whatever" 

रिटर्न, लेकिन पक्ष प्रभाव के रूप में यह स्ट्रिंग "जो कुछ भी" आउटपुट है।

ऑपरेटर चुना गया था क्योंकि इसकी उचित प्राथमिकता थी (ओवरलोडिंग प्राथमिकता नहीं बदल सकती है, और आप नए ऑपरेटरों को परिभाषित नहीं कर सकते हैं) और आकार कुछ हद तक "प्राकृतिक" दिखाई देता है। नोट तथापि कि बाएं पारी ऑपरेटर सिर्फ एक सामान्य ऑपरेटर है और उदाहरण के लिए मूल्यांकन के आदेश के बारे में कोई गारंटी नहीं है:

std::cout << f() << g() << h(); 
यहाँ

उत्पादन f() बुला का परिणाम हो जाएगा, g() बुला का परिणाम के बाद और h() पर कॉल करने के नतीजे के बाद ... लेकिन कार्यों को स्वयं एक अलग क्रम में बुलाया जा सकता है और उदाहरण के लिए h() पहले कहा जा सकता है!

तो एक अर्थ में ऑपरेटर का "अनुक्रम देखो" भ्रामक है, क्योंकि यह आउटपुट के अनुक्रम के बारे में है, लेकिन मूल्यांकन के अनुक्रम के बारे में नहीं है।

2

<< एक ऑपरेटर है, वैसे ही + एक ऑपरेटर है और * एक ऑपरेटर है।

5 + 3 + 2 
((5 + 3) + 2) 

तो कर रहे हैं कि अगले दो:

std::cout << "Hello" << std::endl 
((std::cout << "Hello") << std::endl) 

यह सिर्फ दो ऑपरेंड के साथ एक ऑपरेटर है जिस तरह से निम्नलिखित में बराबर अभिव्यक्तियां हैं। मौलिक प्रकारों के लिए, << और >> ऑपरेटरों को वास्तव में बाएं और दाएं शिफ्ट ऑपरेटर के रूप में जाना जाता है। वे bitwise स्थानांतरण कर प्रदर्शन करते हैं। उदाहरण के लिए, 10 (1010) प्राप्त करने के लिए, 5 (0101) में सभी बिट्स को स्थानांतरित कर देगा।

हालांकि, अधिकांश अन्य ऑपरेटरों के साथ, आप शिफ्ट ऑपरेटर को अधिभारित कर सकते हैं। इनपुट/आउटपुट लाइब्रेरी के मामले में, शिफ्ट ऑपरेटर को स्ट्रीम और इनपुट के लिए एक प्राकृतिक वाक्यविन्यास प्रदान करने के लिए अधिभारित किया जाता है। ऐसा इसलिए है क्योंकि << और >> टोकन की दिशात्मकता एक तरह से बहती है जैसे कुछ एक तरफ बहती है। इन I/O कक्षाओं के साथ, इन ऑपरेटर ओवरलोड्स उस स्ट्रीम के संदर्भ को वापस लौटाते हैं जिसे आप ऑपरेटर कर रहे हैं ताकि उन्हें एक साथ जोड़ा जा सके।

आप एक सदस्य वर्ग operator<< या operator>> प्रदान करके किसी विशेष वर्ग के लिए शिफ्ट ऑपरेटर को अधिभारित कर सकते हैं जो एक तर्क (ऑपरेटर के दाईं ओर ऑपरेंड) लेता है। वैकल्पिक रूप से, आप गैर-सदस्य फ़ंक्शन को उसी नाम से प्रदान कर सकते हैं जो क्रमशः ऑपरेटर के दो ऑपरेंड दो तर्क लेते हैं।

संबंधित मुद्दे