2010-04-23 9 views
5

मैं, मेरे सामने इतने सारे प्रोग्रामर की तरह, अपने बालों को दाएं-ऑफ-मार्ग-मैट्रिक्स-क्लास-इन-सी ++ लिखने से बाहर निकाल रहा हूं। मैंने कभी भी गंभीर ऑपरेटर ओवरलोडिंग नहीं की है और इससे समस्याएं पैदा हो रही हैं। अनिवार्य रूप से,मैं चेनिंग की अनुमति देने के लिए सी ++ ऑपरेटरों को ओवरलोड करने के बारे में कैसे जा सकता हूं?

के माध्यम से कदम उठाकर मैं समस्याओं का कारण बनता हूं।

cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true); 
    Kev *= 4.0f; 
    cMatrix Baz = Kev; 
    Kev = Kev+Baz; //HERE! 

क्या डिबगर के अनुसार हो रहा हो लगता है कि कीव और बाज जोड़ रहे हैं, लेकिन फिर मूल्य खो दिया है और जब यह कीव को फिर नियत की बात आती है, स्मृति बस उसके डिफ़ॉल्ट कुशल मूल्यों है। इस कथन की अनुमति देने के लिए मैं अपने ऑपरेटरों को कैसे अधिभारित कर सकता हूं? मेरा (छीन लिया गया) कोड नीचे है।

//header 
class cMatrix 
{ 
private: 
    float* _internal; 
    UInt32 _r; 
    UInt32 _c; 
    bool _zeroindexed; 

    //fast, assumes zero index, no safety checks 
    float cMatrix::_getelement(UInt32 r, UInt32 c) 
    { 
     return _internal[(r*this->_c)+c]; 
    } 

    void cMatrix::_setelement(UInt32 r, UInt32 c, float Value) 
    { 
     _internal[(r*this->_c)+c] = Value; 
    } 

public: 
    cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed); 
    cMatrix(cMatrix& m); 
    ~cMatrix(void); 

    //operators 
    cMatrix& operator + (cMatrix m); 
    cMatrix& operator += (cMatrix m); 
    cMatrix& operator = (const cMatrix &m); 
}; 

//stripped source file 
cMatrix::cMatrix(cMatrix& m) 
{ 
    _r = m._r; 
    _c = m._c; 
    _zeroindexed = m._zeroindexed; 
    _internal = new float[_r*_c]; 

    UInt32 size = GetElementCount(); 

    for (UInt32 i = 0; i < size; i++) 
    { 
     _internal[i] = m._internal[i]; 
    } 
} 

cMatrix::~cMatrix(void) 
{ 
    delete[] _internal; 
} 
cMatrix& cMatrix::operator+(cMatrix m) 
{ 
    return cMatrix(*this) += m; 
} 

cMatrix& cMatrix::operator*(float f) 
{ 
    return cMatrix(*this) *= f; 
} 

cMatrix& cMatrix::operator*=(float f) 
{ 
    UInt32 size = GetElementCount(); 

    for (UInt32 i = 0; i < size; i++) 
    { 
     _internal[i] *= f; 
    } 

    return *this; 
} 

cMatrix& cMatrix::operator+=(cMatrix m) 
{ 
    if (_c != m._c || _r != m._r) 
    { 
     throw new cCTException("Cannot add two matrix classes of different sizes."); 
    } 
    if (!(_zeroindexed && m._zeroindexed)) 
    { 
     throw new cCTException("Zero-Indexed mismatch."); 
    } 

    for (UInt32 row = 0; row < _r; row++) 
    { 
     for (UInt32 column = 0; column < _c; column++) 
     { 
      float Current = _getelement(row, column) + m._getelement(row, column); 
      _setelement(row, column, Current); 
     } 
    } 

    return *this; 
} 

cMatrix& cMatrix::operator=(const cMatrix &m) 
{ 
    if (this != &m) 
    { 
     _r = m._r; 
     _c = m._c; 
     _zeroindexed = m._zeroindexed; 

     delete[] _internal; 

     _internal = new float[_r*_c]; 

     UInt32 size = GetElementCount(); 

     for (UInt32 i = 0; i < size; i++) 
     { 
      _internal[i] = m._internal[i]; 
     } 
    } 
    return *this; 
    } 

उत्तर

10

आपके ऑपरेटरों + और * को संदर्भ द्वारा संदर्भित नहीं किया जाना चाहिए। आप संदर्भ द्वारा अस्थायी चर लौट रहे हैं। इसके अलावा, आप तर्क मान द्वारा पारित कर रहे हैं जब यह एक स्थिरांक संदर्भ होना चाहिए:

cMatrix cMatrix::operator+(cMatrix const& m) 
{ 
    cMatrix matrix(*this); 
    matrix += m; 
    return matrix; 
} 

cMatrix cMatrix::operator*(float f) 
{ 
    cMatrix matrix(*this); 
    matrix *= m; 
    return matrix; 
} 

आप Boost.Operators पर एक नज़र रखना चाहिए। यह आपको केवल operator*= और operator+= लागू करने देगा और स्वचालित रूप से operator+ और operator* के लिए सही कार्यान्वयन प्रदान करेगा।

पुनश्च: तुम सिर्फ शिक्षण अनुभव के लिए अपने मैट्रिक्स वर्ग को लागू करते हैं, तो Matrix Template Library की तरह अन्य कार्यान्वयन को देखने के लिए संकोच नहीं करते।

पीपीएस: यदि आप बूस्ट का उपयोग नहीं करना चाहते हैं, या यदि आप बस सर्वोत्तम अभ्यास को समझना चाहते हैं, तो बूस्ट.ऑपरेटर पर एक नज़र डालें और जो भी करते हैं वह करें।

+0

मेरा उद्देश्य यह चरण सी ++ एसडीडी लिब के साथ रहना है और यदि संभव हो तो किसी भी अन्य libs को जोड़ने से बचें। बूस्ट आसान है लेकिन एक जानवर भी थोड़ा सा है! – User2400

+1

मैं 'ऑपरेटर +' को गैर-सदस्य के रूप में लागू करना चाहता हूं। अन्य फायदों के अलावा, यह भी एक सी ++ 11 कंपाइलर को एक रावल्यू लीफ की प्रति को अनुकूलित करने की अनुमति देता है टी तर्क अगर आप इसे प्रति मान पास करते हैं। (मेरा जवाब देखें।) – sbi

+1

@fneep: मैं समझता हूं कि आपको अभी भी बूस्ट.ऑपरेटर को ऑपरेटरों को लागू करने के लिए वैचारिक तरीके को समझने के लिए एक नज़र रखना चाहिए। – Sebastian

8

IMO इसके अलावा अधिक भार के विहित प्रपत्र यह है:

class X { 
public: 
    X& operator+=(const X& rhs) { /*add rhs to *this*/ } 
}; 

inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;} 

ही -, *, /, जहां लागू हो जाता है।

ध्यान दें कि + एक प्रतिलिपि देता है, संदर्भ नहीं। यह महत्वपूर्ण है, क्योंकि A+B एक नया मान बनाता है, इसलिए यह किसी मौजूदा संदर्भ का संदर्भ नहीं दे सकता है।
इसके अलावा, यह एक नि: शुल्क कार्य है। आईएमओ बाइनरी ऑपरेटरों के उन लोगों को लागू करना सबसे अच्छा है जो किसी सदस्य के रूप में या नि: शुल्क कार्यों के रूप में नि: शुल्क कार्यों के रूप में कार्यान्वित किए जा सकते हैं, यदि वे अपने ऑपरेटरों को समरूप रूप से व्यवहार करते हैं (जैसा कि + करता है), और सदस्य कार्य के रूप में, यदि वे अपने ऑपरेटरों को असमान रूप से मानते हैं (+= है, जो अपनी बाईं तर्क में परिवर्तन के रूप में। आप एक सदस्य के रूप operator+ लागू हैं, तो आप पर, समारोह const (X operator+(const X& rhs) const) बनाने के लिए इतना है कि यह बाईं ओर निरंतर तत्वों के लिए लागू किया जा सकता है करना होगा।

+0

वही है जो बूस्ट.ऑपरेटर करेगा। – Sebastian

+1

@ सेसशन: हाँ, लेकिन आईएमओ आपको सीखना चाहिए कि बूस्ट का उपयोग करके शॉर्टकट लेने से पहले इसे पहले कैसे करना है।अन्यथा, यदि आप '+ =' के साथ कुछ गलत करते हैं तो आप क्या करने जा रहे हैं और संकलक आपके चेहरे में एक भयानक त्रुटि संदेश को बढ़ावा देता है जो बूस्ट के बेलो में गहराई से इंगित करता है? यह सब के बाद, एक सही-मार्ग-कार्यान्वयन_ है। – sbi

+0

और मुझे लगता है कि सीखने का एक अच्छा तरीका एक वैधानिक कार्यान्वयन की जांच करना है। – Sebastian

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

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