std :: Ostream에서 상속하는 방법은 무엇입니까?
-
12-09-2019 - |
문제
나는 인터넷 검색을 해왔고 이것에 대한 간단한 대답을 찾을 수 없습니다. STL이 일반적으로 그렇듯이 간단해야합니다.
STD :: Ostream에서 공개적으로 상속되는 Myostream을 정의하고 싶습니다. 내 스트림에 무언가가 기록 될 때마다 foo ()에게 전화하고 싶다고 가정 해 봅시다.
class MyOStream : public ostream {
public:
...
private:
void foo() { ... }
}
나는 타조의 공개 인터페이스가 가치가 없다는 것을 이해합니다. 어떻게 할 수 있습니까? 클라이언트가 연산자 << 및 write () 및 myostream에서 ()를 모두 사용할 수 있고 내 클래스의 확장 된 능력을 사용할 수 있기를 원합니다.
해결책
불행히도 간단한 질문이 아닙니다. 당신이 파생해야 할 수업은 basic_
다음과 같은 클래스 basic_ostream
. 그러나 스트림으로부터의 파생은 원하는 것이 아닐 수도 있고, 대신 스트림 버퍼에서 파생 한 다음이 클래스를 사용하여 기존 스트림 클래스를 인스턴스화 할 수 있습니다.
전체 지역은 복잡하지만 그것에 대한 훌륭한 책이 있습니다. 표준 C ++ ioStreams 및 로케일, 더 이상 가기 전에 살펴 보는 것이 좋습니다.
다른 팁
나는 똑같은 일을하는 방법에 대해 머리를 돌리고 있었고 그것이 실제로 그렇게 어렵지 않다는 것을 알았습니다. 기본적으로 타조와 StreamBuf 객체를 서브 클래스하고 버퍼로 타조 자체를 구성합니다. 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;
}
오, 주요 기능이 실제 주요 기능이 아니라는 사실을 무시하십시오. 다른 곳에서 호출 된 네임 스페이스에 있습니다. P
비슷한 효과를 달성하기위한 또 다른 작업 해킹은 템플릿과 구성을 사용하는 것입니다.
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";}
이것이 올바른 솔루션인지는 모르겠지만 STD :: Ostream에서 상속했습니다. STD :: BASIC_STREAMBUF에서 상속 된 버퍼를 사용하고 한 번에 64 자 씩 (또는 플러시 된 경우 적은 경우) 실제 데이터 처리가 수행되는 일반적인 putchars () 메소드로 보냅니다. 또한 사용자 데이터를 제공하는 방법을 보여줍니다.
#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;
}
상속이 아닌 구성. 귀하의 클래스에는 "Traps"가 포함되어 있습니다.