2010-01-13 12 views
23

सी ++ सार वर्ग ऑपरेटर ओवरलोडिंग और इंटरफ़ेस प्रवर्तन सवाल

हैलो सभी, (मूल पोस्ट से संपादित "BaseMessage" से "स्थिरांक BaseMessage &" बदलने के लिए) मैं बहुत सी के ++ नया हूँ, इसलिए मैं आप लोगों को आशा है कि मेरी मदद कर सकते हैं "मेरे तरीकों की त्रुटियों को देखें"।

मेरे पास संदेशों का पदानुक्रम है, और मैं को एक इंटरफेस को लागू करने के लिए एक सार आधार वर्ग का उपयोग करने की कोशिश कर रहा हूं। विशेष रूप से, मैं प्रत्येक व्युत्पन्न संदेश को ओवरलोडेड < < ऑपरेटर प्रदान करने के लिए मजबूर करना चाहता हूं।

जब मैं कुछ इस तरह के साथ ऐसा करने का प्रयास करें:

class BaseMessage 
{ 
public: 

// some non-pure virtual function declarations 
// some pure virtual function declarations 

virtual ostream& operator<<(ostream& stream, const BaseMessage& objectArg) = 0; 

} 

संकलक शिकायत है कि

"त्रुटि: पैरामीटर 'objectArg' की घोषणा नहीं कर सकते हैं सार प्रकार की होनी चाहिए 'BaseMessage'

मेरा मानना ​​है कि यहां "मित्र" मुद्दे भी शामिल हैं, लेकिन जब मैंने इसे घोषित करने की कोशिश की:

virtual friend ostream& operator<<(ostream& stream, const BaseMessage objectArg) = 0;

संकलक एक अतिरिक्त त्रुटि जोड़ा

"त्रुटि: आभासी कार्यों मित्र नहीं हो सकता"

वहाँ सुनिश्चित करने के लिए है कि मेरे व्युत्पन्न (संदेश) कक्षाओं के सभी एक "< <" ostream ऑपरेटर प्रदान एक रास्ता है ?

धन्यवाद बहुत,

स्टीव

+0

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

उत्तर

40

इस के लिए आम सम्मेलन आधार स्तर पर एक friend उत्पादन ऑपरेटर है और यह निजी आभासी समारोह कॉल करने के लिए है सदस्य कार्य, और इसलिए वर्चुअल फ़ंक्शन नहीं हो सकते हैं।

a << b; 

तुम सच कह रहे हैं

a.operator<<(b); 

इस मामले में एक में एक धारा है, न कि अपने वर्ग का एक उदाहरण है, इसलिए ऑपरेटर नहीं किया जा सकता: इस का कारण जब आप कहते हैं कुछ की तरह है कि है आपकी कक्षा का एक सदस्य आपको आम तौर पर इसे एक नि: शुल्क (गैर-सदस्य) फ़ंक्शन बनाना चाहिए, जो उपयुक्त सदस्य फ़ंक्शंस के माध्यम से आपके क्लास इंस्टेंस का उपयोग करता है।

+0

यह एकमात्र कामकाजी समाधान है जिसे मैंने यहां पृष्ठ पर देखा है: हर कोई अपने गधे से बात कर रहा है :) (अपने कोड लोगों को संकलित करने का प्रयास करें!) +1 – jkp

+0

यह बहुत अच्छा काम करता है, धन्यवाद निकोलई मैं इसका उपयोग करने के लिए कई जगह देख सकता हूं पैटर्न। - स्टीव –

+0

मुझे नहीं पता था कि आप इस तरह की कक्षा घोषणा के अंदर सीधे मित्र समारोह को परिभाषित कर सकते हैं। जानकार अच्छा लगा!पाठ्यपुस्तक हमेशा मित्र घोषणा और बाहर परिभाषा डाल देंगे। क्या कक्षा के अंदर सीधे परिभाषित करना एक 'स्वैप' मित्र समारोह के साथ भी काम करता है? –

3

सार वर्ग instantiated नहीं किया जा सकता है, इसलिए ऐसा करते हैं:

virtual ostream& operator<<(ostream& stream, const Base &objectArg) = 0; 

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

इसी तरह स्थैतिक कार्य वर्चुअल नहीं हो सकता क्योंकि इसकी कक्षा विधि उदाहरण विधि नहीं है।

मेरे सुझाव है:

class Base { 
public: 
virtual ostream& print (ostream& stream) const = 0; 
}; 


class Derived :public Base { 
public: 
virtual ostream& print (ostream& stream) const { //do something } 
}; 

ostream& operator <<(ostream& stream, const BaseMessage &objectArg) 
{ 
    return objectArg.print(stream); 
} 
0

समस्या यहाँ है कि "BaseMessage objectArg" कह रही है कि objectArg वस्तु मूल्य द्वारा पारित किया जाना चाहिए।

यह असंभव है क्योंकि आपने कक्षा को अपने शुद्ध वर्चुअल कॉल के साथ सार बनाया है। संदर्भ द्वारा एक पास "बेसमेसेज & ऑब्जेक्टएआरजी" या पॉइंटर "बेसमेसेज * ऑब्जेक्टएआरजी" द्वारा पास किया गया यह त्रुटि दूर हो जाएगी।

मूल्य से गुजरने का अर्थ है कि यह कॉपी कन्स्ट्रक्टर का उपयोग करके चर का एक नया उदाहरण बनाता है। चूंकि आपने यह सुनिश्चित किया है कि बेसमेसेज का उदाहरण बनाना असंभव है, यह नहीं किया जा सकता है।

class Base 
{ 
public: 

    /// don't forget this 
    virtual ~Base(); 

    /// std stream interface 
    friend std::ostream& operator<<(std::ostream& out, const Base& b) 
    { 
     b.Print(out); 
     return out; 
    } 

private: 

    /// derivation interface 
    virtual void Print(std::ostream&) const =0; 
}; 
3

धारा ऑपरेटरों की तरह:

virtual ostream& operator<<(ostream& stream, const BaseMessage objectArg) = 0; 

बस नहीं किया जा सकता

1

ऑपरेटर < <() के लिए घोषणा गलत है। सेशन < < की बाइनरी संस्करण के लिए, दूसरा पैरामीटर घोषित करने के लिए नहीं है - यह अगर सेशन < < वर्ग के एक सदस्य समारोह है this माना जाता है:

virtual ostream& operator<<(ostream& stream) = 0;

इसके अलावा, जैसा कि दूसरों द्वारा उल्लिखित है, स्ट्रीम प्रविष्टि ऑपरेटरों को वैश्विक कार्य होना चाहिए। उन्हें सदस्य कार्य करना सिर्फ काम नहीं करेगा।

कुछ भी आपके प्रश्न से संबंधित नहीं है, लेकिन फिर भी एक समस्या है। आपके मूल कार्यान्वयन में आपने संदर्भ के आधार पर या पॉइंटर द्वारा मूल्य के आधार पर एक सार आधार वर्ग वस्तु पारित की है। जब आप ऐसा करते हैं, तो आप "ऑब्जेक्ट स्लाइस" करते हैं। आपका इरादा, मुझे यकीन है कि, बेस क्लास पॉइंटर को एक पॉलिमॉर्फिक प्रकार को फ़ंक्शन में पास करना था, और फिर फ़ंक्शन कॉल विधियों को पॉलिमॉर्फिक रूप से पास करना था। उदाहरण के लिए, आप इस के लिए इसी तरह कुछ करने के लिए कोशिश कर रहे थे:

#include <cstdio> 
#include <string> 
#include <iostream> 
using namespace std; 

class Base 
{ 
public: 
    virtual void dump() 
    { 
     cout << "Base"; 
    }; 
}; 

class Der : public Base 
{ 
public: 
    void dump() 
    { 
     cout << "Der"; 
    }; 
}; 

void DumpIt(Base b) 
{ 
    b.dump(); 
} 


int main() 
{ 
    Der obj; 
    DumpIt(obj); 
    return 0; 

} 

... और उत्पादन की उम्मीद 'डेर "होने के लिए लेकिन वास्तव में उत्पादन" बेस "की वजह से Object Slicing है। चूंकि डंपआईटी() फ़ंक्शन बेस ऑब्जेक्ट को मान द्वारा लेता है, इसलिए मूल पर आधारित एक नया अस्थायी बेस ऑब्जेक्ट बनाया जाता है। आदेश कार्यक्षमता आप उम्मीद कर रहे थे पाने के लिए, आप संदर्भ द्वारा या सूचक द्वारा पारित करने के लिए की जरूरत है:

void DumpIt(Base & b) 
{ 
    b.dump(); 
} 

इस समारोह से उत्पादन "डेर" है।

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