C ++:ostream和ofstream之间不需要的转换

时间:2018-10-24 19:10:00

标签: c++ file stream persistence overloading

我一直在研究个人字典应用程序,它可以帮助您记住所学单词。它通过CLI进行操作(不要怀疑,这只是一个测试,我对CLI应用程序充满了奇怪的热情)。因此,我当然使用ostream来在CLI上写信息。我习惯于为每个类编写operator<<重载(对于ostream s),以便我可以建立一个多级输出系统(基本上每个对象都可以为自己“说话”)。

为了保留字典对象,我想使用ofstream并用它编写文件。自然,我也为operator<<写了ofstream重载,并且使用了相同的“分层”结构。

结果,我现在每个类中都有两个operator<<重载,例如“ Dictionary”:

ostream& operator<<(ostream&, const Dictionary&);
ofstream& operator<<(ofstream&, const Dictionary&);

(这只是头文件中的声明)

请注意,这两个重载都要做不同事情非常重要。我不想在CLI上使用一些奇怪的面向持久性的特殊格式文本也不是我的文件中用户友好的纯文本。

问题在于,由于ostreamofstream的继承结构, ofstream有时隐式转换为ostream 。当这种情况发生在充满 file 输出操作的堆栈中间时,该程序突然跳入错误的重载并在文件中打印纯文本。

我的问题很简单:是否有一种方法可以避免或还原这些不必要的隐式转换,以使我的程序跳入正确的重载?还是有其他解决此问题的好方法?

编辑1

有人在评论中指出,这不是隐含的共识。 ofstream有时被“视为”其基类ostream。问题在于,在某个时刻对象“忘记”它是一个ofstream,并且丢失了所有与文件有关的信息。从那里开始,只有ostream,这就是我所说的“转换”的意思。

编辑2:

程序中发生“不必要的转换”的确切位置可以在这里找到:

ofstream& operator<<(ofstream& of, const Section& s) {
    return s.print_ofstream(of);
}

因此该运算符过分调用“ print_ofstream”:

ofstream& Section::print_ofstream(ofstream& of) const {
    of << "sec" << Util::ID_TO_STRING(section_id) << ":\n";
    for (pair<Wordlist, Wordlist> pwl : translations) {
        of << '{' << pwl.first << '=' << pwl.second << "}\n";
    }
    of << "#\n";
    return of;
}

请注意,“ pwl”是两个Wordlist的对,因此pwl.first / pwl.second是Wordlist。因此,通常行of << '{' << pwl.first << '=' << pwl.second << "}\n";应该在ofstream中调用operator<< Wordlist重载。但事实并非如此。相反,另一个重载方法称为:

ostream& operator<<(ostream& o, const Wordlist& wl) {
    return wl.print_ostream(o);
}

1 个答案:

答案 0 :(得分:0)

您仅重载了将operator<<DictionarySection等对象流式传输到Wordlist所需的特定std::ofstream,但是{{1} } 继承其他std::ofstreamoperator<<,这些运算符都以std::ostream作为输入,并返回ostream&作为输出。因此,例如,ostream&将返回of << "sec",即使ostream&of,然后该std::ofstream用于后续的ostream&调用直到达到<<。这些就是您正在经历的“隐式转换”。

真正的问题是,为什么要;根据写入的operator<<的类型输出不同的数据?这违反了C ++的流模型。如果确实需要,则必须将std::ostream更改为print_ofstream(ofstream&),然后使用print_ostream(ostream&)动态检测实际的std::ostream派生类型。与dynamic_cast和其他需要它的类相同。

一个更简单,更安全的选择是将标记存储在您的类中,以控制应如何输出其数据,而不管所使用的Wordlist的类型如何。然后,您可以根据需要设置该标志。甚至可以定义一些辅助I / O操纵器在进行std::ostream调用时设置这些标志。