【问题标题】:Inheriting from ifstream从 ifstream 继承
【发布时间】:2011-01-24 09:39:07
【问题描述】:

我可以像这样从 ifstream 继承并从派生类中读取文件吗:

#include <iostream>

using namespace std;

const string usage_str = "Usage: extract <file>";

class File: public ifstream
{
public:
    explicit File(const char *fname, openmode mode = in);
    void extract(ostream& o);
};

File::File(const char *fname, openmode mode)
{
    ifstream(fname, mode);
}

void File::extract(ostream& o)
{
    char ch;
    char buf[512];
    int i = 0;

    while (good()) {
        getline(buf, sizeof(buf));
        o<<buf;
        i++;
    }   
    cout<<"Done "<<i<<" times"<<endl;
}

void msg_exit(ostream& o, const string& msg, int exit_code)
{
    o<<msg<<endl;
    exit(exit_code);
}

int do_extract(int argc, char *argv[])
{
    cout<<"Opening "<<argv[1]<<endl;
    File f(argv[1]);
    if (! f)
        msg_exit(cerr, usage_str, 1);
    f.extract(cout);
    return 0;
}

int main(int argc, char *argv[])
{
    if (argc < 2)
        msg_exit(cout, usage_str, 0);

    do_extract(argc, argv);
    return 0;
}

我希望它读取整个文件,但它只读取一个符号(这不是给定文件的第一个符号)...

【问题讨论】:

  • 好()!那有什么作用?
  • ifstream(fname, mode) 应该移动到初始化列表。您应该在尝试读取数据和使用数据之间进行一些错误检查,而不是仅在该过程的迭代之间进行。
  • 这可能会有所帮助:stackoverflow.com/questions/772355/…
  • 在这种情况下,我更喜欢聚合而不是继承,您仍然可以使用这些方法,而不必担心 ifstream 实际做了什么。

标签: c++ inheritance ifstream


【解决方案1】:

不要从 ifstream 继承。如果您需要更改输入流的行为,请从streambuf 继承,然后围绕它构造一个istream。如果您只想添加助手,请将它们设为全局,以便您可以在任何 istream 上使用它们。

也就是说,您的错误在 File 构造函数中:

File::File(const char *fname, openmode mode)
{
    ifstream(fname, mode);
}

这会构造一个(未命名的)ifstream,然后立即关闭它。你想调用超类的构造函数:

File::File(const char *fname, openmode mode)
  : ifstream(fname, mode);
{

}

【讨论】:

    【解决方案2】:

    我没有看到您的提取函数有问题,但我不明白从 ifstream 派生的意义。

    从一个类派生的目的是覆盖它的虚方法,这样当有人将 istream& 或 ifstream& 传递给一个函数(通常是运算符>>)时,你的覆盖就会被调用。

    与 STL 集合不同,流确实使用层次结构和 v-tables,但新手通常会误解这个概念。

    例如,如果您想更改它使用的缓冲区类型,您可以从 basic_streambuf 派生并使用附加了 streambuf 的简单 istream 或 ostream 对象。

    通过从 iostream 或 streambuf 派生新类无法更改对象的打印或读取方式,也不能扩展 iomanips,您必须围绕正在流式传输的对象使用包装类。

    【讨论】:

      【解决方案3】:

      您缺少对基本构造函数的调用。我想你的意思是:

      File::File(const char *fname, openmode mode) : ifstream(fname, mode)
      {
      
      }
      

      而不是这个:

      File::File(const char *fname, openmode mode)
      {
          ifstream(fname, mode);
      }
      

      现在您可能正在读取一些未初始化内存的内容。第二个(当前)代码只是在堆栈上创建一个新的 ifstream 实例并立即销毁它。

      【讨论】:

      • 尝试读取关闭的流不会给您未初始化的内存;根据 ISO/IEC 14882:1998(E) 27.6.1.3.20 std::getline(char_type *, streamsize) 将始终为 null 终止其结果。不幸的是,代码在读取后没有测试故障位错误代码,因此它没有意识到它得到了一个虚假的空字符串。
      • @bdonlan:感谢您的澄清。
      猜你喜欢
      • 2014-06-09
      • 2018-11-21
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多