Menu
Coddy logo textTech

Stream Operators

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 43 of 104.

The stream insertion (<<) and extraction (>>) operators let you use your custom classes with std::cout and std::cin. Unlike the operators we've covered so far, these must be implemented as non-member functions because the left operand is a stream, not your class.

class Point {
    int x, y;
    
public:
    Point(int x, int y) : x(x), y(y) {}
    
    // Declare as friend to access private members
    friend std::ostream& operator<<(std::ostream& os, const Point& p);
    friend std::istream& operator>>(std::istream& is, Point& p);
};

std::ostream& operator<<(std::ostream& os, const Point& p) {
    os << "(" << p.x << ", " << p.y << ")";
    return os;
}

std::istream& operator>>(std::istream& is, Point& p) {
    is >> p.x >> p.y;
    return is;
}

Both operators return a reference to the stream, enabling chaining like std::cout << p1 << p2. The insertion operator takes the object by const reference since it only reads data, while extraction takes a non-const reference because it modifies the object.

Now you can use Point naturally with streams:

Point p(3, 4);
std::cout << "Location: " << p << std::endl;    // Output: Location: (3, 4)

Point p2(0, 0);
std::cin >> p2;    // Read two integers into p2
challenge icon

Challenge

Easy

Let's build a Temperature class that can be seamlessly used with std::cout and std::cin through stream operator overloading. This is a practical scenario where you want to display temperatures in a readable format and read them from input naturally.

You'll create two files to organize your code:

  • Temperature.h: Define a Temperature class that stores a value in Celsius (as a double) and a unit label (as a char, either 'C' for Celsius or 'F' for Fahrenheit). Your class should have:
    • Private members for the temperature value and unit
    • A default constructor that initializes to 0.0 Celsius
    • A parameterized constructor that takes a value and unit
    • Getters getValue() and getUnit() (both const)
    • Friend declarations for the stream insertion (<<) and extraction (>>) operators

    Implement the stream operators as non-member functions:

    • The insertion operator should output the temperature in the format VALUE UNIT (e.g., 25.5 C or 77.9 F). Use one decimal place for the value.
    • The extraction operator should read a value and a unit character from the stream and store them in the Temperature object.

    Both operators must return a reference to the stream to enable chaining.

  • main.cpp: Read two temperatures from input. Each temperature is provided on a separate line in the format value unit (e.g., 25.5 C).

    Create two Temperature objects using the extraction operator to read them from std::cin. Then output them using the insertion operator in this format:

    Temperature 1: <temp1>
    Temperature 2: <temp2>

    For example, if the input is:

    25.5 C
    98.6 F

    The output should be:

    Temperature 1: 25.5 C
    Temperature 2: 98.6 F

Use std::fixed and std::setprecision(1) from <iomanip> to format the temperature value with exactly one decimal place. Don't forget header guards in your header file.

Cheat sheet

Stream insertion (<<) and extraction (>>) operators allow custom classes to work with std::cout and std::cin. These operators must be implemented as non-member functions because the left operand is a stream object, not your class.

Basic Syntax

class Point {
    int x, y;
    
public:
    Point(int x, int y) : x(x), y(y) {}
    
    // Declare as friend to access private members
    friend std::ostream& operator<<(std::ostream& os, const Point& p);
    friend std::istream& operator>>(std::istream& is, Point& p);
};

std::ostream& operator<<(std::ostream& os, const Point& p) {
    os << "(" << p.x << ", " << p.y << ")";
    return os;
}

std::istream& operator>>(std::istream& is, Point& p) {
    is >> p.x >> p.y;
    return is;
}

Key Points

  • Both operators return a reference to the stream to enable chaining (e.g., std::cout << p1 << p2)
  • The insertion operator (<<) takes the object by const reference since it only reads data
  • The extraction operator (>>) takes a non-const reference because it modifies the object
  • Use friend declarations to allow these non-member functions to access private members

Usage Example

Point p(3, 4);
std::cout << "Location: " << p << std::endl;    // Output: Location: (3, 4)

Point p2(0, 0);
std::cin >> p2;    // Read two integers into p2

Try it yourself

#include <iostream>
#include "Temperature.h"

int main() {
    // TODO: Create two Temperature objects
    
    // TODO: Use the extraction operator (>>) to read two temperatures from std::cin
    
    // TODO: Output the temperatures using the insertion operator (<<)
    // Format:
    // Temperature 1: <temp1>
    // Temperature 2: <temp2>
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming