如何在不使用模板的前提下,用同一函数同时输出至屏幕与文件?
你的写法其实是标准且优雅的方案!
嘿,你的这个实现一点都不怪异——恰恰相反,这是C++里利用多态特性处理输出流的标准写法!
ostream是所有C输出流的基类:cout本身就是ostream的实例,ofstream则是继承自ostream的派生类。用ostream&作为函数参数,能完美接收这两种流对象,这正是面向对象多态思想的核心应用之一,完全符合C的设计规范,扩展性还极强——以后要输出到其他ostream派生类(比如字符串流ostringstream),根本不用修改writeit函数。
不用模板的替代方案
如果确实想要其他实现方式,这里有两种符合你“不用模板”要求的思路:
方案1:自定义多输出流分流器
写一个简单的类来封装多个输出流,让它能把内容同时转发给所有绑定的流,你的writeit函数只需要接收这个分流器对象即可:
#include <iostream> #include <fstream> #include <vector> using namespace std; class MultiOstream { private: vector<ostream*> streams; public: // 添加要绑定的输出流,支持链式调用 MultiOstream& add(ostream& os) { streams.push_back(&os); return *this; } // 重载<<操作符,处理普通数据(这里模板仅用于适配任意数据类型,你的writeit函数无需模板) template <typename T> MultiOstream& operator<<(const T& data) { for (auto stream : streams) { *stream << data; } return *this; } // 专门处理endl这类流操作符 MultiOstream& operator<<(ostream& (*func)(ostream&)) { for (auto stream : streams) { func(*stream); } return *this; } }; // 完全不需要模板的writeit函数 void writeit(MultiOstream& mos, const char* text) { mos << text; } int main() { ofstream myfile("text.txt"); MultiOstream mos; mos.add(cout).add(myfile); // 同时绑定屏幕和文件 writeit(mos, "Hello world\n"); // 也可以直接用分流器输出:mos << "Another test line" << endl; return 0; }
这个方案的优势是灵活性极强,你可以随时添加更多输出目标(比如再加一个日志文件流),而不需要修改writeit函数。
方案2:固定双输出的函数
如果你的需求非常固定,只需要同时输出到文件和屏幕,也可以直接在函数里同时操作两个流,完全不用模板:
#include <iostream> #include <fstream> using namespace std; void writeit(ostream& fileOs, const char* text) { fileOs << text; // 输出到文件 cout << text; // 输出到屏幕 } int main() { ofstream myfile("text.txt"); writeit(myfile, "Hello world"); return 0; }
不过这个方案的缺点也很明显:灵活性差,如果以后要输出到其他地方,必须修改writeit函数本身,不符合开闭原则。
总结
最推荐的还是你最开始的写法,它兼顾了简洁性和扩展性。如果需要一次性输出到多个流,自定义MultiOstream分流器是更优的选择。
内容的提问来源于stack exchange,提问作者Miklos Gergely
相关产品推荐
相关产品推荐

