반응형
operator<< 삽입 연산자
클래스를 선언하고 구현할 때 가장 익숙하지 않은 연산자라고 한다면 개인적으로 삽입 연산자를 꼽고 싶다. 보통은 직접 구현하지 않고 다른 사람이 작성한 클래스에서 발견되고는 하는데 해당 연산자를 어떻게 사용하는지에 대해서는 깊게 생각을 해본 적이 없었다. 하지만 알게 되면 생각보다 간단한 법이라는 것을 우린 알고 있다. 이번 기회에 간단하게 짚고 넘어가 보자.
operator<<는 삽입 연산자(Insertion Operator)라고 불린다. 원래는 비트 단위 왼쪽 시프트(Bitwise Left Shift)를 수행하는 연산자이지만, C++ 표준 입출력 라이브러리에서 출력 스트림에 데이터를 보낼 때 사용하는 용도로 오버로딩 되기에 오히려 삽입 연산자로 널리 쓰인다.
사용자 정의 객체 출력
기본 타입(int, double 등) 외에 내가 직접 만든 클래스나 구조체를 cout << 객체; 처럼 출력하고 싶을 때 operator<<를 오버로딩 한다.
예제 코드
삽입 연산자를 구현한 MyClass와 삽입 연산자를 구현하지 않은 MyClass2가 어떻게 쓰이는지에 대해서 살펴보자.
#include <iostream>
#include <list>
using namespace std;
class MyClass
{
public:
MyClass(int a, int b)
{
this->a = a;
this->b = b;
}
virtual ~MyClass() {}
private:
int a;
int b;
friend std::ostream& operator<<(std::ostream& os, MyClass& myclass)
{
return os << "(" << myclass.a << ":" << myclass.b << ")";
}
};
class MyClass2
{
public:
MyClass2(int a, int b)
{
this->a = a;
this->b = b;
}
virtual ~MyClass2() {}
int a;
int b;
};
int main()
{
std::cout << "hello, world." << std::endl;
MyClass mc(1, 3);
std::cout << mc << std::endl;
operator<<(std::cout, mc) << std::endl;
MyClass2 mc2(1, 3);
//std::cout << mc2 << std::endl; // error!
std::cout << "(" << mc2.a << ":" << mc2.b << ")" << std::endl;
}

std::cout << mc << std::endl;
삽입 연산자를 오버로딩하면 마치 문자열을 쓰듯이 std::cout에 연결해서 바로 사용자 정의한 형태로 출력이 가능하다.
std::cout << mc << std::endl;
operator<<(std::cout, mc) << std::endl;
해당 두 코드는 사실 동일한 내용을 표시하고 있는 것이다. 컴파일러가 위의 코드를 만나면 내부적으로 아래처럼 자동 변환해서 실행하는 것이다.
구현 규칙
- 전역 함수로 정의하는 경우 : std::cout은 클래스 내부 멤버가 아니므로 클래스 외부에서 정의해야 한다.
- friend 키워드를 사용해서 정의하는 경우 : 클래스의 private 멤버에 접근해야 한다면 클래스 내부에서 friend로 선언한다.
- 참조 반환: 연속된 출력(Chaining)을 위해 std::ostream&를 반환해야 한다.
삽입 연산자를 멤버 변수로 구현해 보기
class MyClass
{
public:
MyClass(int a, int b)
{
this->a = a;
this->b = b;
}
virtual ~MyClass() {}
private:
int a;
int b;
public:
std::ostream& operator<<(std::ostream& os)
{
return os << "(" << a << ":" << b << ")";
}
};
mc << std::cout;
mc.operator<<(std::cout);
MyClass 멤버 함수로 선언 시에는 원래 보던 형태와 반대로 된다.
정리하자면
- 삽입 연산자를 재정의하면 std::cout << 에 연결해서 내가 원하는 형태로 문자열을 출력할 수 있다.
- 마치 문자열처럼 바로 연결이 가능해서 사용하기 때문에 코드 보기가 편하다.
- 삽입 연산자를 전역 함수로 정의하거나 사용자 정의 클래스 내부에 friend 키워드를 사용해야 한다.
- 멤버 변수로 정의 가능하지만 멤버 변수로 정의하고 사용하면 호출 순서가 반대로 된다.
'프로그래밍 > C++' 카테고리의 다른 글
| 생산자 - 소비자 패턴으로 스레드 공부하기 (0) | 2026.02.21 |
|---|---|
| 바쁜 대기(Busy Waiting)에 대해서 알아보자 (0) | 2026.02.01 |
| 상호배제란 무엇인가? (0) | 2026.02.01 |
| thread_local 키워드에 대해서 (0) | 2026.01.31 |
| RAII에 대해서 알아보자 (0) | 2026.01.26 |
댓글