Читаем Thinking In C++. Volume 2: Practical Programming полностью

Even though the FILE pointer is private, it isn’t particularly safe because fp( ) retrieves it. Since the only effect seems to be guaranteed initialization and cleanup, why not make it public or use a struct instead? Notice that while you can get a copy of f using fp( ), you cannot assign to f— that’s completely under the control of the class. Of course, after capturing the pointer returned by fp( ), the client programmer can still assign to the structure elements or even close it, so the safety is in guaranteeing a valid FILE pointer rather than proper contents of the structure.

If you want complete safety, you must prevent the user from directly accessing the FILE pointer. Some version of all the normal file I/O functions must show up as class members so that everything you can do with the C approach is available in the C++ class:.

//: C04:Fullwrap.h

// Completely hidden file IO

#ifndef FULLWRAP_H

#define FULLWRAP_H

class File {

  std::FILE* f;

  std::FILE* F(); // Produces checked pointer to f

public:

  File(); // Create object but don't open file

  File(const char* path,

       const char* mode = "r");

  ~File();

  int open(const char* path,

           const char* mode = "r");

  int reopen(const char* path,

             const char* mode);

  int getc();

  int ungetc(int c);

  int putc(int c);

  int puts(const char* s);

  char* gets(char* s, int n);

  int printf(const char* format, ...);

  size_t read(void* ptr, size_t size,

              size_t n);

  size_t write(const void* ptr,

size_t size, size_t n);

  int eof();

  int close();

  int flush();

  int seek(long offset, int whence);

  int getpos(fpos_t* pos);

  int setpos(const fpos_t* pos);

  long tell();

  void rewind();

  void setbuf(char* buf);

  int setvbuf(char* buf, int type, size_t sz);

  int error();

  void clearErr();

};

#endif // FULLWRAP_H ///:~

This class contains almost all the file I/O functions from . (vfprintf( ) is missing; it is used to implement the printf( ) member function.).

File has the same constructor as in the previous example, and it also has a default constructor. The default constructor is important if you want to create an array of File objects or use a File object as a member of another class in which the initialization doesn’t happen in the constructor, but some time after the enclosing object is created.

The default constructor sets the private FILE pointer f to zero. But now, before any reference to f, its value must be checked to ensure it isn’t zero. This is accomplished with F( ), which is private because it is intended to be used only by other member functions. (We don’t want to give the user direct access to the underlying FILE structure in this class.)[38] 

This approach is not a terrible solution by any means. It’s quite functional, and you could imagine making similar classes for standard (console) I/O and for in-core formatting (reading/writing a piece of memory rather than a file or the console).

The big stumbling block is the runtime interpreter used for the variable argument list functions. This is the code that parses your format string at runtime and grabs and interprets arguments from the variable argument list. It’s a problem for four reasons.

1.Even if you use only a fraction of the functionality of the interpreter, the whole thing gets loaded into your executable. So if you say printf("%c", 'x');, you’ll get the whole package, including the parts that print floating-point numbers and strings. There’s no standard option for reducing the amount of space used by the program.

2.Because the interpretation happens at runtime, you can’t get rid of a performance overhead. It’s frustrating because all the information is there in the format string at compile time, but it’s not evaluated until runtime. However, if you could parse the arguments in the format string at compile time, you could make direct function calls that have the potential to be much faster than a runtime interpreter (although the printf( ) family of functions is usually quite well optimized).

3.A worse problem is that the format string is not evaluated until runtime: there can be no compile-time error checking. You’re probably familiar with this problem if you’ve tried to find bugs that came from using the wrong number or type of arguments in a printf( ) statement. C++ makes a big deal out of compile-time error checking to find errors early and make your life easier. It seems a shame to throw type safety away for an I/O library, especially because I/O is used a lot.

Перейти на страницу:

Похожие книги

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT