Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #6599 > unrolled thread

I/O abstract class suggestions

Started byjakash3 <jakashthree@gmail.com>
First post2011-06-10 19:54 -0700
Last post2011-06-12 14:43 +0000
Articles 8 — 4 participants

Back to article view | Back to comp.lang.c++


Contents

  I/O abstract class suggestions jakash3 <jakashthree@gmail.com> - 2011-06-10 19:54 -0700
    Re: I/O abstract class suggestions Ian Collins <ian-news@hotmail.com> - 2011-06-11 14:59 +1200
      Re: I/O abstract class suggestions jakash3 <jakashthree@gmail.com> - 2011-06-10 20:03 -0700
        Re: I/O abstract class suggestions Ian Collins <ian-news@hotmail.com> - 2011-06-11 16:04 +1200
    Re: I/O abstract class suggestions Paavo Helde <myfirstname@osa.pri.ee> - 2011-06-11 04:06 -0500
      Re: I/O abstract class suggestions jakash3 <jakashthree@gmail.com> - 2011-06-11 12:35 -0700
        Re: I/O abstract class suggestions Paavo Helde <myfirstname@osa.pri.ee> - 2011-06-18 06:35 -0500
      Re: I/O abstract class suggestions Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-06-12 14:43 +0000

#6599 — I/O abstract class suggestions

Fromjakash3 <jakashthree@gmail.com>
Date2011-06-10 19:54 -0700
SubjectI/O abstract class suggestions
Message-ID<4e58c83a-eefa-4231-8e7d-506632e14a5f@f31g2000pri.googlegroups.com>
I've made In and Out abstract base classes which I plan to have File,
Socket, and Console classes base some of their methods on. These
interfaces will have method names like those from the C library as
well as formatted insertion and extraction streams. Please give
feedback and suggestions on how I can add to or improve this
interface.

class In {
public:
	virtual int getc() = 0;
	virtual char* gets(char* s, int size) = 0;
	virtual int scanf(const char* format, ...) = 0;
	virtual size_t read(void* ptr, size_t size, size_t nmemb) = 0;
	virtual In& operator>> (bool& val) = 0;
	virtual In& operator>> (short& val) = 0;
	virtual In& operator>> (unsigned short& val) = 0;
	virtual In& operator>> (int& val) = 0;
	virtual In& operator>> (unsigned int& val) = 0;
	virtual In& operator>> (long& val) = 0;
	virtual In& operator>> (unsigned long& val) = 0;
	virtual In& operator>> (float& val) = 0;
	virtual In& operator>> (double& val) = 0;
	virtual In& operator>> (long double& val) = 0;
	virtual In& operator>> (const void*& val) = 0;
	virtual In& operator>> (char& c) = 0;
	virtual In& operator>> (signed char& c) = 0;
	virtual In& operator>> (unsigned char& c) = 0;
	virtual In& operator>> (char*& s) = 0;
	virtual In& operator>> (String& s) = 0;
	virtual In& operator>> (Charp& s) = 0;
};

class Out {
public:
	virtual int putc(int c) = 0;
	virtual int puts(const char* s) = 0;
	virtual int printf(const char* format, ...) = 0;
	virtual size_t write(const void* ptr, size_t size, size_t nmemb) = 0;
	virtual Out& operator<< (bool val) = 0;
	virtual Out& operator<< (short val) = 0;
	virtual Out& operator<< (unsigned short val) = 0;
	virtual Out& operator<< (int val) = 0;
	virtual Out& operator<< (unsigned int val) = 0;
	virtual Out& operator<< (long val) = 0;
	virtual Out& operator<< (unsigned long val) = 0;
	virtual Out& operator<< (float val) = 0;
	virtual Out& operator<< (double val) = 0;
	virtual Out& operator<< (long double val) = 0;
	virtual Out& operator<< (const void* val) = 0;
	virtual Out& operator<< (char c) = 0;
	virtual Out& operator<< (signed char c) = 0;
	virtual Out& operator<< (unsigned char c) = 0;
	virtual Out& operator<< (const char* s) = 0;
	virtual Out& operator<< (String s) = 0;
	virtual Out& operator<< (Charp s) = 0;
};

[toc] | [next] | [standalone]


#6600

FromIan Collins <ian-news@hotmail.com>
Date2011-06-11 14:59 +1200
Message-ID<95g402FnkjU2@mid.individual.net>
In reply to#6599
On 06/11/11 02:54 PM, jakash3 wrote:
> I've made In and Out abstract base classes which I plan to have File,
> Socket, and Console classes base some of their methods on. These
> interfaces will have method names like those from the C library as
> well as formatted insertion and extraction streams. Please give
> feedback and suggestions on how I can add to or improve this
> interface.

Why don't you keen the standard iostream objects and create specialised 
streambuf objects?  The streambuf is where the low level, device 
specific IO operations are located.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#6601

Fromjakash3 <jakashthree@gmail.com>
Date2011-06-10 20:03 -0700
Message-ID<2bf4596b-162a-492d-b5e9-77c5fc528cb5@e17g2000prj.googlegroups.com>
In reply to#6600
On Jun 10, 7:59 pm, Ian Collins <ian-n...@hotmail.com> wrote:

> Why don't you keen the standard iostream objects and create specialised
> streambuf objects?  The streambuf is where the low level, device
> specific IO operations are located.
>
> --
> Ian Collins

You may have a good point, but I'm not very familiar with the C++
library. Well, I guess you could say that I like to reinvent the
wheel.

[toc] | [prev] | [next] | [standalone]


#6603

FromIan Collins <ian-news@hotmail.com>
Date2011-06-11 16:04 +1200
Message-ID<95g7qdFnkjU3@mid.individual.net>
In reply to#6601
On 06/11/11 03:03 PM, jakash3 wrote:
> On Jun 10, 7:59 pm, Ian Collins<ian-n...@hotmail.com>  wrote:
>
>> Why don't you keen the standard iostream objects and create specialised
>> streambuf objects?  The streambuf is where the low level, device
>> specific IO operations are located.
>
> You may have a good point, but I'm not very familiar with the C++
> library. Well, I guess you could say that I like to reinvent the
> wheel.

The streambuf is designed to be derived from, it has appropriate virtual 
methods (underflow, overflow and sync give you most of what's needed) to 
support specialisation.

Implementing a streambuf to read from a file descriptor is a great 
learning exercise.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#6610

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2011-06-11 04:06 -0500
Message-ID<Xns9F017B2CC7C3Bmyfirstnameosapriee@216.196.109.131>
In reply to#6599
jakash3 <jakashthree@gmail.com> wrote in
news:4e58c83a-eefa-4231-8e7d-506632e14a5f@f31g2000pri.googlegroups.com: 

> I've made In and Out abstract base classes which I plan to have File,
> Socket, and Console classes base some of their methods on. These
> interfaces will have method names like those from the C library as
> well as formatted insertion and extraction streams. Please give
> feedback and suggestions on how I can add to or improve this
> interface.

Let's assume you seriously want to reinvent the wheel and create your own 
replacement for std::istream/std::ostream facility. See also boost.format 
library for conversions and formatting.

There are several facets to this task:
  - transportation of bits from/to different places (like socket, memory-
mapped file, etc.)
  - converting the data to/from C++ variables 
  - formatting the data in the external file
  - adjustments of formatting according to locale settings
  - for text I/O, the charset choice (Unicode, ISO-Latin-1 etc).
  - for text I/O, the encoding of the charset (UTF-8, UTF-16, UTF-32 
etc).

All these tasks are to some extent orthogonal and should ideally be 
expressed by some orthogonal means. The std::*stream facility uses run-
time polymorphism (mostly virtual functions in the streambuf classes) for 
the first, static polymorphism (overloads and templates) for the second, 
and special manipulator objects for the third. The C printf/scanf 
interface brings the converting and formatting aspects more closely 
together in the same format codes. For both, locale settings are 
controlled by separate functions working 'behind the scenes'. Charset and 
encoding are a mess and provided by a mix of locale and templating 
(wchar_t vs. char etc). One can certainly do better than the current 
std:: solution, but I'm afraid this is not an easy task.

Now let's see how this all works with your proposed interface:

  - it is not consistent in that it provides raw I/O (read, getc) in the 
same footing to formatted I/O functions. IMO it would be better to have 
this functionality in separate classes.

  - if you plan to use inheritance for supporting different I/O sources, 
then the formatted I/O functions should most probably remain the same, so 
they should not be virtual. Probably they should be templated instead.

  - the ellipsis style functions (printf, scanf) are not type-safe and 
can cause lots of problems at run-time. In C++ one can do much better, 
see e.g. boost.format library.

  - there are no means of controlling the exact formatting (e.g. printing 
an integer in hexadecimal or octal notation). The std::stream 
manipulators are not a very good solution as their scope is not really 
expressed in the source code. The printf-style format codes are better in 
that sense, but are harder to make type-safe.

  - there are no means of controlling the locale-specific behavior. IMO 
it should be explicit in the interface, too bad that it is hidden in the 
interface.

  - charsets and their encoding are not even touched, as far as I can 
see. 

  - for C-style functions there are specific C-style deficiences, see 
below:

> class In {
> public:
>      virtual int getc() = 0;
>      virtual char* gets(char* s, int size) = 0;

This should work with std::string instead of char (or std::wstring? 
std::basic_string?)

>      virtual int scanf(const char* format, ...) = 0;

This is really unsafe.

>      virtual size_t read(void* ptr, size_t size, size_t nmemb) = 0;

This should probably work with std::vector instead of void*.

>      virtual In& operator>> (bool& val) = 0;
>      virtual In& operator>> (short& val) = 0;
>      virtual In& operator>> (unsigned short& val) = 0;
>      virtual In& operator>> (int& val) = 0;
>      virtual In& operator>> (unsigned int& val) = 0;
>      virtual In& operator>> (long& val) = 0;
>      virtual In& operator>> (unsigned long& val) = 0;
>      virtual In& operator>> (float& val) = 0;
>      virtual In& operator>> (double& val) = 0;
>      virtual In& operator>> (long double& val) = 0;
>      virtual In& operator>> (const void*& val) = 0;
>      virtual In& operator>> (char& c) = 0;
>      virtual In& operator>> (signed char& c) = 0;
>      virtual In& operator>> (unsigned char& c) = 0;
>      virtual In& operator>> (char*& s) = 0;
>      virtual In& operator>> (String& s) = 0;
>      virtual In& operator>> (Charp& s) = 0;

As said, these belong to another interface, should be non-virtual and 
templated instead:

template<typename T> In& operator>>(T& val);

In my experience, most files are not textual, so all these bells and 
whistles wasted on the on-the-fly textual formatting and conversions are 
not really worth it IMO. Maybe you really want to create some hierarchy 
of binary I/O classes instead, this would be a much easier task. 

Cheers
Paavo

[toc] | [prev] | [next] | [standalone]


#6627

Fromjakash3 <jakashthree@gmail.com>
Date2011-06-11 12:35 -0700
Message-ID<6f1c7196-a197-4bd5-9b71-822ff52f980f@z4g2000prk.googlegroups.com>
In reply to#6610
@Paavo Helde I'm actually a student still learning and you brought up
very good points. I never thought about specific output formatting
options and locales. Perhaps I should include methods to set the
options for string and number output for streams or maybe even create
variations on the class in different namespaces for different locales.
Btw I forgot to mention that String and Charp types referenced in this
class are a string class and character pointer class respectively.
Charp can be treated like a regular character pointer except there
would be an option to automatically call free to the character pointer
upon destruction. My String class will return it's internal character
pointer when casted as a char ptr or passed to a function that expects
one.

[toc] | [prev] | [next] | [standalone]


#6873

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2011-06-18 06:35 -0500
Message-ID<Xns9F08945FCC481myfirstnameosapriee@216.196.109.131>
In reply to#6627
jakash3 <jakashthree@gmail.com> wrote in news:6f1c7196-a197-4bd5-9b71-
822ff52f980f@z4g2000prk.googlegroups.com:

> @Paavo Helde I'm actually a student still learning and you brought up
> very good points. I never thought about specific output formatting
> options and locales. Perhaps I should include methods to set the
> options for string and number output for streams or maybe even create
> variations on the class in different namespaces for different locales.
> Btw I forgot to mention that String and Charp types referenced in this
> class are a string class and character pointer class respectively.
> Charp can be treated like a regular character pointer except there
> would be an option to automatically call free to the character pointer
> upon destruction. 

So what is the purpose of existence of the Charp class? A string class 
like std::string does about the same except it additionally stores the 
length of the string. A char* wrapper would be useful quite rarely, for 
example if you receive a lot of char* pointers from a C-style library, 
which need to be passed again to some C-style library working with char* 
interfaces. But in that case the pointers would be probably released with 
some library-specific release function, so hardcoding free() would be a 
mistake. 

The point is that for working with strings one often needs to know its 
length. With char* interfaces one is forced to recalculate the length 
over and over again, which can easily ruin any perceived performance 
benefits of char* over a std::string-like class. Also, supporting two 
different string classes in the code is a headache.

> My String class will return it's internal character
> pointer when casted as a char ptr or passed to a function that expects
> one.

Not a good idea. MS tried this with their CString class and it is 
generally accepted this was a mistake. Their own compiler now emits 
warnings whenever a CString is implicitly converted to a const char* 
pointer.

If this is your own fun project, then of course there is nothing wrong 
with reinventing the string classes and learning from the mistakes. If 
you are doing this for something more serious, then I strongly suggest to 
ditch your own string and stream classes and go with std::string and 
iostreams. There are a few quirks this way as well, but the end result 
will most probably be better than whatever you can invent by yourself. 

Note that for advanced usage of standard strings and streams you need to 
learn quite a bit about std::basic_string and std::basic_streambuf class 
templates.

hth
Paavo

[toc] | [prev] | [next] | [standalone]


#6655

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2011-06-12 14:43 +0000
Message-ID<slrniv9k51.gtj.grahn+nntp@frailea.sa.invalid>
In reply to#6610
On Sat, 2011-06-11, Paavo Helde wrote:
> jakash3 <jakashthree@gmail.com> wrote in
> news:4e58c83a-eefa-4231-8e7d-506632e14a5f@f31g2000pri.googlegroups.com: 
>
>> I've made In and Out abstract base classes which I plan to have File,
>> Socket, and Console classes base some of their methods on. These
>> interfaces will have method names like those from the C library as
>> well as formatted insertion and extraction streams. Please give
>> feedback and suggestions on how I can add to or improve this
>> interface.
...

> In my experience, most files are not textual, so all these bells and 
> whistles wasted on the on-the-fly textual formatting and conversions are 
> not really worth it IMO.

That varies with your environment, I think. I'm on Unix, and most file
formats there are text. If you design your own, you normally choose
text. Many popular networking protocol are too (since he mentioned
sockets).

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .  .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web