2009-04-21 12 views
25

मैं चारों ओर घूम रहा हूं और मुझे बस इसका आसान जवाब नहीं मिल रहा है। और यह सरल होना चाहिए, क्योंकि एसटीएल आमतौर पर है।std :: ostream से कैसे प्राप्त किया जाए?

मैं माईओएसट्रीम को परिभाषित करना चाहता हूं जो std :: ostream से सार्वजनिक रूप से विरासत में मिलता है। मान लें कि मैं foo() को हर बार अपनी स्ट्रीम में कुछ लिखने के लिए कॉल करना चाहता हूं।

class MyOStream : public ostream { 
public: 
    ... 
private: 
    void foo() { ... } 
} 

मैं समझता हूँ कि ostream की सार्वजनिक इंटरफ़ेस गैर आभासी है, इसलिए यह कैसे किया जा सकता है? मैं चाहता हूं कि ग्राहक ऑपरेटर < < दोनों का उपयोग करने में सक्षम हों और MyOStream पर() और put() लिखें और मेरी कक्षा की विस्तारित क्षमता का उपयोग करें।

+3

एसटीएल सरल हो सकता है, लेकिन यह सी ++ मानक पुस्तकालय का केवल एक हिस्सा है। आईओस्ट्रीम लाइब्रेरी के पास एसटीएल (एक बार क्या था) के साथ कुछ लेना देना नहीं है। एसटीएल मूल रूप से contianers + iterators + एल्गोरिदम है। Iostreams, लोकेशंस और सभी जिनमें एक पूरी तरह से अलग उत्पत्ति है, और आम तौर पर काम करने के लिए दर्द होता है;) – jalf

उत्तर

19

दुर्भाग्य से यह एक साधारण सवाल नहीं है। जिन वर्गों को आप प्राप्त करना चाहते हैं वे basic_ कक्षाएं हैं, जैसे basic_ostream। हालांकि, स्ट्रीम से व्युत्पन्न वह नहीं हो सकता है जो आप चाहते हैं, आप इसके बजाय स्ट्रीम बफर से प्राप्त करना चाहते हैं, और फिर मौजूदा कक्षा वर्ग को चालू करने के लिए इस कक्षा का उपयोग करें।

पूरा क्षेत्र जटिल है, लेकिन इसके बारे में Standard C++ IOStreams and Locales के बारे में एक उत्कृष्ट पुस्तक है, जिसका सुझाव है कि आप आगे जाने से पहले एक नज़र डालें।

+0

मैं इस पुस्तक की मेरी प्रतिलिपि देखने जा रहा था, लेकिन आपने मुझे बचा लिया है। +1 – Evan

+0

@anon मुझे वेब पर अस्ट्रीम का कोई संदर्भ नहीं मिल रहा है। यह क्या है? –

0

संरचना, विरासत नहीं। आपकी कक्षा में एक ओस्ट्रीम & "wraps" है, और इसके आगे (foo() को कॉल करने के बाद)।

+0

कृपया कुछ कोड पोस्ट करें जो दिखाता है कि यह मौजूदा << ऑपरेटरों के साथ कैसे काम करेगा। और नोट करें foo() हर बार ऐसे ऑपरेटर का उपयोग किया जाता है। –

+6

संरचना हमेशा सबसे अच्छा समाधान नहीं है, जैसे विरासत नहीं है। ओस्ट्रीम के लिए इसके लिए एक दर्जन अधिभारित ऑपरेटर लागू किए गए हैं, आप उम्मीद नहीं करते हैं कि किसी भी कक्षा में एक छोटी कार्यक्षमता जोड़ने के लिए किसी को वास्तव में ओस्ट्रीम के सभी सार्वजनिक इंटरफेस को फिर से लिखना पड़े। – Michael

4

मुझे नहीं पता कि यह सही समाधान है, लेकिन मुझे इस तरह std :: ostream से विरासत मिली है। यह std :: basic_streambuf से विरासत में प्राप्त एक बफर का उपयोग करता है और एक समय में 64 वर्ण प्राप्त करता है (या फ़्लश होने पर कम) और उन्हें सामान्य जेन चार्स() विधि में भेजता है जहां डेटा का वास्तविक प्रबंधन किया जाता है। यह भी दर्शाता है कि उपयोगकर्ता डेटा कैसे देना है।

Live Example

#include <streambuf> 
#include <ostream> 
#include <iostream> 

//#define DEBUG 

class MyData 
{ 
    //example data class, not used 
}; 

class MyBuffer : public std::basic_streambuf<char, std::char_traits<char> > 
{ 

public: 

    inline MyBuffer(MyData data) : 
    data(data) 
    { 
     setp(buf, buf + BUF_SIZE); 
    } 

protected: 

    // This is called when buffer becomes full. If 
    // buffer is not used, then this is called every 
    // time when characters are put to stream. 
    inline virtual int overflow(int c = Traits::eof()) 
    { 
#ifdef DEBUG 
     std::cout << "(over)"; 
#endif 
     // Handle output 
     putChars(pbase(), pptr()); 
     if (c != Traits::eof()) { 
      char c2 = c; 
      // Handle the one character that didn't fit to buffer 
      putChars(&c2, &c2 + 1); 
     } 
     // This tells that buffer is empty again 
     setp(buf, buf + BUF_SIZE); 

     return c; 
    } 

    // This function is called when stream is flushed, 
    // for example when std::endl is put to stream. 
    inline virtual int sync(void) 
    { 
     // Handle output 
     putChars(pbase(), pptr()); 
     // This tells that buffer is empty again 
     setp(buf, buf + BUF_SIZE); 
     return 0; 
    } 

private: 

    // For EOF detection 
    typedef std::char_traits<char> Traits; 

    // Work in buffer mode. It is also possible to work without buffer. 
    static const size_t BUF_SIZE = 64; 
    char buf[BUF_SIZE]; 

    // This is the example userdata 
    MyData data; 

    // In this function, the characters are parsed. 
    inline void putChars(const char* begin, const char* end){ 
#ifdef DEBUG 
     std::cout << "(putChars(" << static_cast<const void*>(begin) << 
      "," << static_cast<const void*>(end) << "))"; 
#endif 
     //just print to stdout for now 
     for (const char* c = begin; c < end; c++){ 
      std::cout << *c; 
     } 
    } 

}; 

class MyOStream : public std::basic_ostream< char, std::char_traits<char> > 
{ 

public: 

    inline MyOStream(MyData data) : 
    std::basic_ostream< char, std::char_traits<char> >(&buf), 
    buf(data) 
    { 
    } 

private: 

    MyBuffer buf; 

}; 

int main(void) 
{ 
    MyData data; 
    MyOStream o(data); 

    for (int i = 0; i < 8; i++) 
     o << "hello world! "; 

    o << std::endl; 

    return 0; 
} 
19

एक और काम कर रहे एक समान प्रभाव को प्राप्त करने हैक टेम्पलेट और संरचना

class LoggedStream { 
public: 
    LoggedStream(ostream& _out):out(_out){} 
    template<typename T> 
    const LoggedStream& operator<<(const T& v) const {log();out << v;return *this;} 
protected: 
    virtual void log() = 0; 
    ostream& out; 
}; 

class Logger : LoggedStream { 
    void log() { std::cerr << "Printing" << std::endl;} 
}; 

int main(int,char**) {LoggedStream(std::cout) << "log" << "Three" << "times";} 
+0

यह 'हेक्स' या' एंडल' – shoosh

+0

जैसी सामग्री का समर्थन नहीं करता है क्यों नहीं? 'टी' को' std :: हेक्स' प्रकार मिलेगा। –

+6

@ElazarLeibovich: यह 'std :: hex' के लिए काम करता है लेकिन' std :: endl' या 'std :: flush' (और शायद कुछ अन्य) के लिए नहीं। ऐसा इसलिए है क्योंकि यह उपयुक्त फ़ंक्शन प्रकार को टी को हल नहीं कर सकता है। 'लॉग इनस्ट्रीम' में निम्नलिखित जोड़ना समस्या को हल करता है: 'लॉगडस्ट्रीम कॉन्स एंड ऑपरेटर << (std :: ostream & (* F) (std :: ostream &)) const {F (out); वापसी * ​​यह; } ' –

12

मैं कैसे एक ही बात करने के लिए चारों ओर मेरे सिर घूम रहा था उपयोग करने के लिए है और मैं पता चला यह है वास्तव में मुश्किल नहीं है। असल में केवल ओस्ट्रीम और स्ट्रीमबफ ऑब्जेक्ट्स को उपclass, और ostream स्वयं बफर के रूप में निर्माण। std :: streambuf से आभासी अतिप्रवाह() स्ट्रीम को भेजे गए प्रत्येक चरित्र के लिए बुलाया जाएगा। अपने उदाहरण को फिट करने के लिए मैंने अभी एक foo() फ़ंक्शन बनाया है और इसे बुलाया है।

struct Bar : std::ostream, std::streambuf 
{ 
    Bar() : std::ostream(this) {} 

    int overflow(int c) 
    { 
     foo(c); 
     return 0; 
    } 


    void foo(char c) 
    { 
     std::cout.put(c); 

    } 
}; 

void main() 
{ 
    Bar b; 
    b<<"Look a number: "<<std::hex<<29<<std::endl; 
} 

ओह और इस तथ्य को अनदेखा करें कि मुख्य कार्य वास्तविक मुख्य कार्य नहीं है। यह किसी अन्य जगह से नामित नामस्थान में है; पी

+2

पूरी तरह से काम करता है! स्वीकार्य उत्तर होना चाहिए, हालांकि यह एक पुराना सवाल है। – ZXcvbnM

+0

मैं ZXcvbnM से सहमत हूं, यह स्वीकार्य उत्तर होना चाहिए। स्वीकृत उत्तर में एक उपयोगी संदर्भ होता है लेकिन वास्तव में समाधान प्रदान नहीं करता है। बेन एक साधारण कामकाजी समाधान प्रदान करता है। +1। – sgbirch

+0

अंत में मुझे इतने लंबे समय तक इसकी तलाश करने के बाद एक समाधान मिला, यह लोगों के जैसा स्वीकार्य उत्तर होना चाहिए। – user0103

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