【问题标题】:Difficulty overloading operator<< for file handling class难以为文件处理类重载运算符<<
【发布时间】:2016-02-06 12:14:41
【问题描述】:

我必须:

用构造函数定义一个File_handle 类,该类接受一个字符串参数(文件名),在构造函数中打开文件,并在析构函数中关闭它。

据我了解,此类用于提供 RAII,我正在尝试使用 FILE* 作为基本数据结构来实现该类,我的目标基本上是使 FILE* 成为智能指针:

fileHandler.h

// Class CFile_handler based on FILE*
class CFile_handler {
public:
    CFile_handler();                                           // default constructor   
    CFile_handler(const std::string& fileName,                 // constructor
                  const std::string& mode);     
    ~CFile_handler ();                                          // destructor

    // modifying member function
    void open_file(const std::string& fileName, 
                   const std::string& mode);

protected:
    typedef FILE* ptr;

private:
    CFile_handler(const CFile_handler&);                        // prevent copy creation
    CFile_handler& operator= (const CFile_handler&);            // prevent copy assignment

    ptr c_style_stream;                                         // data member
};

fileHandler.cpp

// Class CFile_handler member implementations
// default constuctor
CFile_handler::CFile_handler() {

}

// constructor
CFile_handler::CFile_handler(const std::string& fileName, const std::string& mode = "r")
    : c_style_stream( fopen( fileName.c_str(), mode.c_str() ) ) 
{

}

// destructor
CFile_handler::~CFile_handler() {
    if (c_style_stream) fclose(c_style_stream);
}

// Modifying member functions
void CFile_handler::open_file(const std::string& fileName, const std::string& mode) {
    c_style_stream = ( fopen( fileName.c_str(), mode.c_str() ) );
}

但是,我在重载 I/O operators&lt;&lt; / &gt;&gt; 时遇到了困难,因为我不知道如何实现它们。

如何重载 operator&lt;&lt; 以使该类与 iostream 对象一起使用?

编辑:

正如@LokiAstari 提出的,从istream 继承并定义自己的streambuf 会是更好的策略。

有人可以举例说明处理FILE*streambuf 的实现吗?


我要提供的是:

CFile_handler fh("filename.txt", "r");

std::string file_text;
fh >> file_text;

或:

CFile_handler fh("filename.txt", "w");

fh << "write this to file";

【问题讨论】:

  • 您需要更具体地了解您想要做什么。您是否尝试将内容放入带有file << 1;?或者您是否尝试将 CFile_handler 本身输出到 iostream 中,例如 std::cout &lt;&lt; file
  • @Puppy 是的,我正在尝试实现上述两个操作。我只包含了operator&lt;&lt; 的声明以显示我认为它的外观,以避免“你尝试过什么”的问题。
  • 为什么反对票和关闭票?你能添加评论吗?
  • @simplicisveritatis 好吧,通常你不会从标准库继承类,而只是使用它们。我仍然不清楚你想通过CFile_handler 类实现什么。包装 FILE* 仅在您需要在构造时从您的班级外部传递这些内容时才有意义。
  • 如果您希望它与所有现有的流功能一起使用(而不是为所有内容编写自己的运算符istream 派生并在内部定义自己的streambuf处理文件*。

标签: c++ oop iostream raii


【解决方案1】:

您可以使用 std::streambuf 派生 std::streams 的类型来处理 FILE*

#include <iostream>
#include <stdio.h>

class OutputFilePointerStream: public std::ostream
{
    class OutputFilePointerStreamBuf: public std::streambuf
    {
        FILE*   buffer;
        public:
            OutputFilePointerStreamBuf(std::string const& fileName)
            {
                buffer  = fopen(fileName.c_str(), "w");
            }
            ~OutputFilePointerStreamBuf()
            {
                fclose(buffer);
            }
            virtual std::streamsize xsputn(const char* s, std::streamsize n) override
            {
                static char format[30];
                sprintf(format, "%%.%lds", n);
                fprintf(buffer, format, s);
                return n;
            }
    };
    OutputFilePointerStreamBuf       buffer;
    public:
        OutputFilePointerStream(std::string const& fileName)
            : std::ostream(nullptr)
            , buffer(fileName)
        {
            rdbuf(&buffer);
        }
};

int main()
{
    OutputFilePointerStream      fileStream("Test");

    fileStream << "Testing: " << 5 << "><\n";
    fileStream << "Line Again\n";
}

【讨论】:

  • 效果很好!我想xsputn 涉及内部缓冲区机制,这可能与写入输出有关,这在逻辑上意味着我必须编写类似xgetn 的东西才能从"r" 模式的输入中读取。无论如何,感谢您提供有用的示例!
  • @simplicisveritatis:参见streambuf 查看虚拟保护成员函数
【解决方案2】:

您的operator&lt;&lt; 函数是将CFile_handler 对象输出到C++ 输出流,而不是用于输出 CFile_handler 对象。

要输出到CFile_handler 对象,您有两种选择:

  1. 作为成员函数

    CFile_handler& CFile_handler::operator<<(int value)
    {
        // Output an integer to the contained file
        return *this;
    }
    
  2. 或者作为一个以CFile_handler 引用作为第一个参数的非成员函数:

    CFile_handler& operator<<(CFile_handler& file, int value)
    {
        // Output an integer to the file contained in `file`
        return file;
    }
    

对于上述两种变体,您可以这样做,例如

CFile_handler my_file(...);
my_file << 1234;

【讨论】:

  • 感谢您的宝贵时间和帮助。我已经编辑了问题以阐明我想要实现的功能。能否在实现的方向上发表一些意见,即使用哪些函数来写入数据成员ptr
  • @simplicisveritatis 假设ptrFILE*,那么在示例中显示只需执行例如fprintf(c_style_stream, "%d", value); 在函数中。
  • @simplicisveritatis 对于阅读,只需执行相反的操作(例如,operator&gt;&gt;,通过引用获取 value 参数以便您可以更改它,使用 fscanf)。
  • @simplicisveritatis C++ 流类只不过是一个简单的类,有很多 operator&lt;&lt;operator&gt;&gt; 重载。在这方面,您的CFile_handler 流,如果我理解您的作业,那么您的课程应该是“流”。
  • 抱歉造成误解,所以我必须为所有内置类型(intchardouble 等)编写 operator&lt;&lt; / &gt;&gt;s 作为 C 的包装器具有相应格式设置("%d" 等)的函数(fprintf()fscanf()),对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 2011-07-21
  • 1970-01-01
相关资源
最近更新 更多