C
Christopher Benson-Manica
(To the extent that this is a rehash of earlier questions, sorry.)
I feel like I'm starting to get the hang of how to make classes work
with << and >>, so now I have the (possibly dumb) idea to create
generic interfaces that use these, making it easy to subclass our
existing classes and make them behave a little better in the C++
world. I'm going to describe what I'm doing in some detail - feel
free to interject criticism at any point, since I'm not at all sure
what can be done better...
To start with: Create a class/interface Receivable that serves to
buffer data written to it (currently, a lot of code we have takes only
const char *'s for writing):
class Receivable // Buffered line input via <<
{
protected:
std:stringstream outbuf;
public:
virtual void ProcessInput( std::string& s )=0;
template <class T> void Buffer( const T& t );
template <class T> Receivable& operator<< ( const T& t );
void Flush() {ProcessInput(outbuf.str()+"\n");}
};
template <class T> void Receivable::Buffer( const T& t )
{
outbuf << t;
std::string& buf=outbuf.str();
if( buf[buf.length()-1]=='\n' ) {
ProcessInput( buf );
}
outbuf.clear();
outbuf.str( "" );
}
template <class T> Receivable& Receivable:perator<< ( const T& t )
{
Buffer( t );
return( *this );
}
Okay, great, maybe. Now create an interface Stringizable that allows
classes that implement it to appear on the right side of << operators:
class Stringizable
{
virtual const char* ToString()=0; // returns const char * because
// that's what a lot of code
// already returns
};
Uh-huh, you say. But how to make Stringizables work with the <<
operator? Maybe
template <class T>
T& __fastcall operator<< ( const T& t, const Stringizable& s )
{
t << s.ToString();
return( t );
}
Fine and dandy, as long as T doesn't implement Stringizable, eh? How
can I make it that general? But onward - now I should be able to put
these interfaces to work in my previously-mentioned TLSFileStream
class:
class
TLSFileStream : public TLSFile, public Receivable, public Stringizable
{
typedef TLSFile Inherited;
public:
CPCHAR __fastcall ToString() {return(AsString());} // TLSFile
void __fastcall ProcessInput( std::string& s )
{
Inherited::Write( s.c_str() ); // implemented by TLSFile
}
~TLSFileStream() {Flush();}
};
So theoretically, I should be able to do
TLSFileStream fs1, fs2;
....
fs1 << fs2;
But, as I noted above, TLSFileStream implements both interfaces, and
thus the compiler can't figure it out.
Help/suggestions, please
I feel like I'm starting to get the hang of how to make classes work
with << and >>, so now I have the (possibly dumb) idea to create
generic interfaces that use these, making it easy to subclass our
existing classes and make them behave a little better in the C++
world. I'm going to describe what I'm doing in some detail - feel
free to interject criticism at any point, since I'm not at all sure
what can be done better...
To start with: Create a class/interface Receivable that serves to
buffer data written to it (currently, a lot of code we have takes only
const char *'s for writing):
class Receivable // Buffered line input via <<
{
protected:
std:stringstream outbuf;
public:
virtual void ProcessInput( std::string& s )=0;
template <class T> void Buffer( const T& t );
template <class T> Receivable& operator<< ( const T& t );
void Flush() {ProcessInput(outbuf.str()+"\n");}
};
template <class T> void Receivable::Buffer( const T& t )
{
outbuf << t;
std::string& buf=outbuf.str();
if( buf[buf.length()-1]=='\n' ) {
ProcessInput( buf );
}
outbuf.clear();
outbuf.str( "" );
}
template <class T> Receivable& Receivable:perator<< ( const T& t )
{
Buffer( t );
return( *this );
}
Okay, great, maybe. Now create an interface Stringizable that allows
classes that implement it to appear on the right side of << operators:
class Stringizable
{
virtual const char* ToString()=0; // returns const char * because
// that's what a lot of code
// already returns
};
Uh-huh, you say. But how to make Stringizables work with the <<
operator? Maybe
template <class T>
T& __fastcall operator<< ( const T& t, const Stringizable& s )
{
t << s.ToString();
return( t );
}
Fine and dandy, as long as T doesn't implement Stringizable, eh? How
can I make it that general? But onward - now I should be able to put
these interfaces to work in my previously-mentioned TLSFileStream
class:
class
TLSFileStream : public TLSFile, public Receivable, public Stringizable
{
typedef TLSFile Inherited;
public:
CPCHAR __fastcall ToString() {return(AsString());} // TLSFile
void __fastcall ProcessInput( std::string& s )
{
Inherited::Write( s.c_str() ); // implemented by TLSFile
}
~TLSFileStream() {Flush();}
};
So theoretically, I should be able to do
TLSFileStream fs1, fs2;
....
fs1 << fs2;
But, as I noted above, TLSFileStream implements both interfaces, and
thus the compiler can't figure it out.
Help/suggestions, please