Programming Language & Its Applications β Virtual Functions and File Handling, NEC licence examination syllabus (Nepal Engineering Council).
Why cout, a file and a string all accept the same << β one inheritance tree, four destinations.
void print(std::ostream& os) works unchanged whether it prints to the screen, writes a file, builds a string, or feeds a network socket. That is polymorphism paying for itself in a library you use every day β and it is the direct application of the virtual functions from earlier in this section. It is also why unit-testing output is easy in C++: pass a std::ostringstream instead of cout and assert on the resulting string. Search "dependency injection ostream testing"; this one design choice makes output testable without touching the filesystem.#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct Student { int roll; std::string name; double marks; };
/* ONE function, works with ANY ostream */
void printTable(std::ostream &os,
const std::vector<Student> &v) {
os << "Roll Name Marks\n"
<< "-----------------------------\n";
double total = 0;
for (const auto &s : v) {
os << s.roll << " " << s.name;
for (size_t i = s.name.size(); i < 16; i++) os << ' ';
os << s.marks << "\n";
total += s.marks;
}
os << "average: " << total / v.size() << "\n";
}
int main() {
std::vector<Student> v = {
{101, "Ram Bahadur", 87.5},
{102, "Sita Devi", 91.0},
{103, "Hari Prasad", 76.5}
};
/* destination 1: the console */
std::cout << "--- to cout ---\n";
printTable(std::cout, v);
/* destination 2: a file β same function */
{ std::ofstream f("report.txt");
printTable(f, v); }
std::cout << "--- written to report.txt ---\n";
/* destination 3: a string β same function */
std::ostringstream ss;
printTable(ss, v);
std::string captured = ss.str();
std::cout << "--- captured " << captured.size()
<< " chars into a std::string ---\n";
/* cerr is unbuffered and a separate channel */
std::cerr << "this goes to standard error\n";
/* istringstream: parse FROM a string */
std::istringstream in("104 Gita 68.0");
Student g;
in >> g.roll >> g.name >> g.marks;
std::cout << "parsed from a string: " << g.roll << " "
<< g.name << " " << g.marks << "\n";
return 0;
}
Output:
--- to cout ---
Roll Name Marks
-----------------------------
101 Ram Bahadur 87.5
102 Sita Devi 91
103 Hari Prasad 76.5
average: 85
--- written to report.txt ---
--- captured 149 chars into a std::string ---
this goes to standard error
parsed from a string: 104 Gita 68
ostringstream case is worth dwelling on. It turns "produce output" into "produce a string", which means any function written against std::ostream& is automatically testable β no temporary files, no capturing stdout. If you take one design habit from this topic, make it "accept std::ostream&, not std::cout".
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
/* number -> string (the pre-C++11 to_string) */
template <typename T>
std::string toStr(const T &v) {
std::ostringstream os; os << v; return os.str();
}
/* string -> number, with failure detection */
template <typename T>
bool fromStr(const std::string &s, T &out) {
std::istringstream is(s);
return (is >> out) && is.eof(); /* fully consumed? */
}
/* split a CSV line β getline with a custom delimiter */
std::vector<std::string> split(const std::string &line, char d) {
std::vector<std::string> out;
std::istringstream is(line);
std::string field;
while (std::getline(is, field, d)) out.push_back(field);
return out;
}
int main() {
std::cout << " toStr(42) = [" << toStr(42) << "]\n";
std::cout << " toStr(3.14) = [" << toStr(3.14) << "]\n";
std::cout << " toStr(true) = [" << toStr(true) << "]\n";
int n;
std::cout << std::boolalpha;
std::cout << " \"123\" -> " << fromStr("123", n)
<< " n=" << n << "\n";
std::cout << " \"12abc\" -> " << fromStr("12abc", n)
<< " (rejected: trailing junk)\n";
std::cout << " \"abc\" -> " << fromStr("abc", n)
<< " (rejected: not a number)\n";
auto f = split("101,Ram Bahadur,87.5,Kathmandu", ',');
std::cout << " CSV -> " << f.size() << " fields:\n";
for (size_t i = 0; i < f.size(); i++)
std::cout << " [" << i << "] " << f[i] << "\n";
return 0;
}
Output:
toStr(42) = [42]
toStr(3.14) = [3.14]
toStr(true) = [1]
"123" -> true n=123
"12abc" -> false (rejected: trailing junk)
"abc" -> false (rejected: not a number)
CSV -> 4 fields:
[0] 101
[1] Ram Bahadur
[2] 87.5
[3] Kathmandu
ios::sync_with_stdio(false) to disconnect them from C's stdio and gain several-fold speedups. C++20 fixed this properly with std::format, which is type-safe like iostreams, fast like printf, and readable like Python's f-strings: std::format("{:.2f}", x). C++23 added std::print. Search "std::format vs iostream performance" β it is the future of C++ output and worth learning early.ios_base β basic_ios β istream/ostream β iostream, with the file and string variants below. Name the four predefined streams and state that cerr is unbuffered while cout, cin and clog are buffered. Explain that cin is tied to cout, which is why prompts appear without endl. Be ready to show one function taking std::ostream& working with console, file and string destinations β that demonstrates the whole point of the hierarchy.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loadingβ¦