2009-01-24 20 views
171

मै मैट्रिक्स संचालन के लिए सी ++ में एक छोटी मैट्रिक्स लाइब्रेरी लिख रहा हूं। हालांकि मेरा संकलक शिकायत करता है, जहां इससे पहले नहीं था। यह कोड 6 महीने के लिए शेल्फ पर छोड़ा गया था और बीच में मैंने अपने कंप्यूटर को डेबियन एक्ट से लेनी (जी ++ (डेबियन 4.3.2-1.1) 4.3.2 से अपग्रेड किया था) हालांकि मुझे उबंटू सिस्टम पर एक ही समस्या है जी ++।एक ostream के लिए << ऑपरेटर को ठीक से अधिभार कैसे करें?

namespace Math 
{ 
    class Matrix 
    { 
    public: 

     [...] 

     friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix); 
    } 
} 

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

matrix.cpp:459: error: 'std::ostream& Math::Matrix::operator<<(std::ostream&, const Math::Matrix&)' must take exactly one argument

:

using namespace Math; 

std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) { 

    [...] 

} 

इस संकलक द्वारा दिए गए त्रुटि है

यहाँ मेरी मैट्रिक्स वर्ग के प्रासंगिक हिस्सा है मैं इस त्रुटि से थोड़ी उलझन में हूं, लेकिन फिर फिर से मेरे सी ++ ने उन 6 राक्षसों के बहुत सारे काम करने के बाद थोड़ा सा जंगली हो गया है चौथाई। :-)

उत्तर

99

आपने अपना कार्य friend के रूप में घोषित कर दिया है। यह कक्षा का सदस्य नहीं है। आपको कार्यान्वयन से Matrix:: हटा देना चाहिए। friend का अर्थ है कि निर्दिष्ट फ़ंक्शन (जो कक्षा का सदस्य नहीं है) निजी सदस्य चर का उपयोग कर सकता है। जिस तरह से आपने फ़ंक्शन को कार्यान्वित किया है, वह Matrix कक्षा के लिए एक उदाहरण विधि की तरह है जो गलत है।

+6

और आपको इसे मैथ नेमस्पेस के अंदर घोषित करना चाहिए (न केवल नामस्थान मैथ के उपयोग से)। –

+1

'ऑपरेटर <<' को 'मठ' के नामस्थान में क्यों होना चाहिए? ऐसा लगता है कि यह वैश्विक नामस्थान में होना चाहिए। मैं मानता हूं कि मेरा कंपाइलर चाहता है कि यह 'मठ' के नामस्थान में हो, लेकिन यह मुझे समझ में नहीं आता है। –

58

,

namespace Math 
{ 
    class Matrix 
    { 
     public: 

     [...] 


    } 
    std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix); 
} 

अपने कार्यान्वयन में Mehrdad जवाब देने के लिए जोड़ने के लिए

std::ostream& operator<<(std::ostream& stream, 
        const Math::Matrix& matrix) { 
    matrix.print(stream); //assuming you define print for matrix 
    return stream; 
} 
+3

मुझे समझ में नहीं आता कि यह एक कम वोट क्यों है, यह स्पष्ट करता है कि आप ऑपरेटर को नामस्थान में घोषित कर सकते हैं और यहां तक ​​कि एक मित्र के रूप में भी नहीं और आप ऑपरेटर को कैसे घोषित कर सकते हैं। – kal

+2

मेहरद के उत्तर में कोड का कोई स्निपेट नहीं था, इसलिए मैंने अभी जोड़ा है कि कक्षा के बाहर नामस्थान में इसे स्थानांतरित करके क्या काम कर सकता है। – kal

+0

मैं आपकी बात समझता हूं, मैंने केवल आपके दूसरे स्निपेट को देखा। लेकिन अब मैं देखता हूं कि आप ऑपरेटर को कक्षा से बाहर ले गए। सलाह के लिये धन्यवाद। –

114

बस आप के बारे में एक अन्य संभावना बता: मुझे लगता है कि के लिए दोस्त परिभाषाओं का उपयोग पसंद:

namespace Math 
{ 
    class Matrix 
    { 
    public: 

     [...] 

     friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) { 
      [...] 
     } 
    }; 
} 

फ़ंक्शन स्वचालित रूप से आसपास के नामस्थान Math (ई में लक्षित किया जाएगा ven हालांकि इसकी परिभाषा उस वर्ग के दायरे में दिखाई देती है) लेकिन तब तक दिखाई नहीं देगी जब तक कि आप एक मैट्रिक्स ऑब्जेक्ट के साथ ऑपरेटर < < पर कॉल न करें जो तर्क निर्भर लुकअप को उस ऑपरेटर परिभाषा को ढूंढ देगा। यह कभी-कभी संदिग्ध कॉल के साथ मदद कर सकता है, क्योंकि यह मैट्रिक्स के अलावा तर्क प्रकारों के लिए अदृश्य है। अपनी परिभाषा लिखते समय, आप मैट्रिक्स और मैट्रिक्स में परिभाषित नामों को सीधे संदर्भित कर सकते हैं, कुछ संभवतः लंबे उपसर्ग के साथ नाम अर्हता प्राप्त किए बिना और Math::Matrix<TypeA, N> जैसे टेम्पलेट पैरामीटर प्रदान किए बिना।

+0

इस उत्तर के लिए धन्यवाद यह मेरे लिए बहुत उपयोगी था। – tommyk

+4

मुझे लगता है कि यह उत्तर स्वीकार किए जाने से बेहतर है। धन्यवाद! – PolyMesh

48

यह मानते हुए कि हम std::ostream से प्राप्त सभी वर्गों के लिए operator << अधिक भार Matrix वर्ग को संभालने के लिए (और Matrix वर्ग के लिए << अधिक भार नहीं) के बारे में बात कर रहे हैं, यह शीर्षक में गणित नाम स्थान के बाहर अधिभार समारोह की घोषणा करने के लिए और अधिक समझ में आता है ।

केवल एक दोस्त फ़ंक्शन का उपयोग करें यदि कार्यक्षमता सार्वजनिक इंटरफेस के माध्यम से हासिल नहीं की जा सकती है।

Matrix.h

namespace Math { 
    class Matrix { 
     //... 
    }; 
} 
std::ostream& operator<<(std::ostream&, const Math::Matrix&); 

ध्यान दें कि ऑपरेटर अधिभार नाम स्थान के बाहर घोषित किया जाता है।

Matrix.cpp

using namespace Math; 
using namespace std; 

ostream& operator<< (ostream& os, const Matrix& obj) { 
    os << obj.getXYZ() << obj.getABC() << '\n'; 
    return os; 
} 

दूसरी ओर, यदि आपके अधिभार समारोह जरूरत करता है एक दोस्त अर्थात निजी और संरक्षित सदस्यों के लिए उपयोग की जरूरत है किया जाएगा।

math.h

namespace Math { 
    class Matrix { 
     public: 
      friend std::ostream& operator<<(std::ostream&, const Matrix&); 
    }; 
} 

आप संलग्न करने के लिए सिर्फ using namespace Math; के बजाय एक नाम स्थान ब्लॉक के साथ समारोह परिभाषा की जरूरत है।

Matrix.cpp

using namespace Math; 
using namespace std; 

namespace Math { 
    ostream& operator<<(ostream& os, const Matrix& obj) { 
     os << obj.XYZ << obj.ABC << '\n'; 
     return os; 
    }     
} 
20

सी ++ 14 आप किसी भी वस्तु जो एक टी :: प्रिंट (std :: ostream &) स्थिरांक है मुद्रित करने के लिए निम्न टेम्पलेट का उपयोग कर सकते है; सदस्य।

template<class T> 
auto operator<<(std::ostream& os, const T& t) -> decltype(t.print(os), os) 
{ 
    t.print(os); 
    return os; 
} 
+1

असल में यह सी ++ 11 में भी काम करता प्रतीत होता है। – jotik

+0

दिलचस्प समाधान! एक सवाल - जहां इस ऑपरेटर को वैश्विक दायरे में घोषित किया जाना चाहिए? मुझे लगता है कि यह सभी प्रकार के लिए दृश्यमान होना चाहिए जिसका उपयोग इसे templatize करने के लिए किया जा सकता है? – barney

+0

@barney यह आपके नामस्थान में हो सकता है जो कक्षाओं के साथ इसका उपयोग करता है। – QuentinUK

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