C++에서 istream
, ostream
, sstream
는 모두 표준 라이브러리에서 제공하는 스트림 클래스입니다. 이 클래스들은 입출력 작업을 추상화하여 파일, 콘솔, 문자열 등을 손쉽게 다룰 수 있도록 도와줍니다. 각각에 대해 자세히 설명하겠습니다.
1. istream
istream
은 입력 스트림을 나타내는 클래스입니다. 이 클래스는 데이터 입력을 위한 다양한 메소드를 제공합니다. istream
의 주요 역할은 데이터의 입력을 관리하는 것입니다.
주요 기능
- 연산자 오버로딩 (
>>
, stream insertion operator): 데이터를 입력받을 때 사용하는 연산자입니다. - ex) cin
- cin은 c++ 표준 라이브러리에서 제공하는 객체로, istream 클래스의 객체임
-
int x; std::cin >> x; // 콘솔로부터 정수를 입력받아 x에 저장
- 멤버 함수:
get()
: 한 문자를 읽습니다.getline()
: 한 줄을 읽습니다.read()
: 바이너리 데이터를 읽습니다.
예시
#include <iostream>
using namespace std;
int main() {
int num;
cout << "Enter a number: ";
cin >> num;
cout << "You entered: " << num << endl;
return 0;
}
2. ostream
ostream
은 출력 스트림을 나타내는 클래스입니다. 이 클래스는 데이터 출력을 위한 다양한 메소드를 제공합니다. ostream
의 주요 역할은 데이터를 출력하는 것입니다.
주요 기능
- 연산자 오버로딩 (
<<
, stream extraction operator): 데이터를 출력할 때 사용하는 연산자입니다. - ex) cout
- cout은 c++ 표준 라이브러리에서 제공하는 객체로, ostream 클래스의 객체임
-
int x = 10; std::cout << x; // 콘솔에 정수를 출력
- 멤버 함수:
put()
: 한 문자를 출력합니다.write()
: 바이너리 데이터를 출력합니다.
예시
#include <iostream>
using namespace std;
int main() {
int num = 10;
cout << "The number is: " << num << endl;
return 0;
}
3. stringstream
stringstream
는 문자열 스트림을 나타내는 클래스입니다. 이 클래스는 istream
과 ostream
의 기능을 모두 포함하며, 문자열을 입출력할 수 있도록 합니다. 주로 문자열을 파싱하거나 생성하는 데 사용됩니다.
주요 기능
- 연산자 오버로딩 (
<<
,>>
): 문자열을 입력받고 출력하는 데 사용됩니다.std::stringstream ss; ss << "123"; int x; ss >> x; // 문자열 "123"을 정수 123으로 변환하여 x에 저장
- 멤버 함수:
str()
: 스트림의 내용을 문자열로 반환하거나 설정합니다.
예시
#include <iostream>
#include <sstream>
using namespace std;
int main() {
stringstream ss;
ss << 123 << " " << 456;
int a, b;
ss >> a >> b;
cout << "a: " << a << ", b: " << b << endl;
return 0;
}
이러한 스트림 클래스를 사용하면 C++에서 다양한 입출력 작업을 쉽게 처리할 수 있습니다.
C++에서는 stringstream
클래스를 사용하여 java.io.BufferedReader
와 유사한 방식으로 데이터를 버퍼에 저장한 후, 한 번에 입출력할 수 있습니다. stringstream
은 문자열 스트림을 제공하므로, 메모리 내에서 버퍼링된 입출력 작업을 수행할 수 있습니다.
예시: stringstream
을 사용한 버퍼링된 입출력
코드 설명:
- 데이터를
stringstream
에 쓰고, 나중에 한 번에 출력합니다. stringstream
을 사용하여 문자열을 버퍼에 저장합니다.- 필요한 시점에 버퍼에 저장된 데이터를 출력합니다.
코드:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
// stringstream 객체를 생성
stringstream buffer;
// 버퍼에 데이터를 작성
buffer << "Hello, " << "world!" << endl;
buffer << "This is a buffered output example." << endl;
// 더 많은 데이터를 버퍼에 작성
for (int i = 1; i <= 5; ++i) {
buffer << "Line " << i << ": This is some buffered text." << endl;
}
// 버퍼에서 데이터를 읽어와서 한 번에 출력
cout << buffer.str();
// 버퍼를 지우고 재사용할 수도 있습니다
buffer.str(""); // 버퍼를 비운다
buffer.clear(); // 상태 플래그를 초기화
// 버퍼에 다시 데이터를 작성
buffer << "New data after clearing the buffer." << endl;
// 다시 버퍼의 내용을 출력
cout << buffer.str();
return 0;
}
설명:
stringstream buffer;
는 문자열 스트림 객체를 생성합니다.buffer << "Hello, " << "world!" << endl;
은 여러 문자열을 버퍼에 차례대로 저장합니다.- 반복문을 통해 여러 줄의 텍스트를 버퍼에 추가로 저장합니다.
cout << buffer.str();
은 버퍼에 저장된 모든 데이터를 한 번에 출력합니다.buffer.str("");
과buffer.clear();
은 버퍼를 비우고 상태 플래그를 초기화하여, 버퍼를 다시 사용할 수 있도록 합니다.- 버퍼에 새로운 데이터를 추가하고 다시 출력할 수 있습니다.
이 방식은 메모리 내에서 버퍼링된 입출력을 가능하게 하여, 파일이나 네트워크 스트림과 같은 실제 입출력 작업에서 발생하는 비용을 줄일 수 있습니다. 또한, 데이터를 버퍼에 저장한 후 나중에 한 번에 처리할 수 있어 효율적인 입출력 작업을 수행할 수 있습니다.
예제: 사용자 정의 클래스 Person
에 >>
와 <<
연산자 오버로딩
사용자 정의 클래스에 >>와 << 연산자를 오버로딩하는 예제를 소개하겠습니다. 이를 통해 클래스 객체를 istream과 ostream을 통해 입출력할 수 있습니다.
클래스 정의:
Person
클래스는 이름과 나이를 저장합니다.>>
연산자는 입력 스트림으로부터 데이터를 읽어Person
객체에 저장합니다.<<
연산자는Person
객체의 데이터를 출력 스트림에 출력합니다.
코드:
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string name;
int age;
public:
Person() : name(""), age(0) {}
Person(string name, int age) : name(name), age(age) {}
// >> 연산자 오버로딩 (입력)
friend istream& operator>>(istream& is, Person& person) {
cout << "Enter name: ";
is >> person.name;
cout << "Enter age: ";
is >> person.age;
return is;
}
// << 연산자 오버로딩 (출력)
friend ostream& operator<<(ostream& os, const Person& person) {
os << "Name: " << person.name << ", Age: " << person.age;
return os;
}
};
int main() {
Person p1;
// >> 연산자 사용 (입력)
cin >> p1;
// << 연산자 사용 (출력)
cout << p1 << endl;
return 0;
}
설명:
- 클래스 정의:
Person
클래스는name
과age
멤버를 가집니다.- 기본 생성자와 매개변수를 받는 생성자를 정의합니다.
- >> 연산자 오버로딩:
istream& operator>>(istream& is, Person& person)
는istream
객체를 통해 사용자로부터 이름과 나이를 입력받아Person
객체에 저장합니다.friend
키워드를 사용하여 이 연산자가Person
클래스의 비공개 멤버에 접근할 수 있도록 합니다.
- << 연산자 오버로딩:
ostream& operator<<(ostream& os, const Person& person)
는Person
객체의 이름과 나이를 출력 스트림에 출력합니다.friend
키워드를 사용하여 이 연산자가Person
클래스의 비공개 멤버에 접근할 수 있도록 합니다.
- main 함수:
Person
객체를 생성하고,cin >> p1;
을 통해 사용자로부터 데이터를 입력받습니다.cout << p1 << endl;
을 통해 객체의 데이터를 출력합니다.
이 예제를 통해 사용자 정의 클래스에 >>
와 <<
연산자를 오버로딩하여 스트림 입출력을 쉽게 구현할 수 있습니다. 이 방법을 사용하면 클래스 객체를 표준 입출력 함수와 동일하게 다룰 수 있어 코드의 일관성과 가독성이 향상됩니다.
istream
과 ostream
연산자 오버로딩 함수에서 반환되는 istream&
와 ostream&
는 연속적인 입출력 작업을 가능하게 하고, 스트림 상태를 유지하는 중요한 역할을 합니다. 각각의 역할을 자세히 설명하겠습니다.
istream& operator>>(istream& is, Person& person)
이 함수는 istream
객체를 통해 Person
객체에 데이터를 입력하는 역할을 합니다. 반환값으로 istream&
를 반환하는 이유는 다음과 같습니다:
- 연속적인 입력 가능:
istream&
를 반환함으로써 연속된 입력 연산을 할 수 있습니다.- 예를 들어,
cin >> p1 >> p2;
와 같이 여러 객체에 연속적으로 입력할 수 있습니다.
- 스트림 상태 유지:
- 반환된
istream&
는 스트림의 상태(예: 실패 플래그)를 유지합니다. - 입력 중에 오류가 발생하면, 반환된 스트림 객체에 오류 상태가 설정되어 이후의 입력 연산에 영향을 미칩니다.
- 반환된
- 연산자 체이닝:
istream&
를 반환함으로써, 다른 연산자와의 체이닝을 가능하게 합니다.- 예를 들어,
cin >> p1 >> p2
와 같이 하나의 입력 스트림으로 여러 객체를 연속적으로 입력받을 수 있습니다.
ostream& operator<<(ostream& os, const Person& person)
이 함수는 ostream
객체를 통해 Person
객체의 데이터를 출력하는 역할을 합니다. 반환값으로 ostream&
를 반환하는 이유는 다음과 같습니다:
- 연속적인 출력 가능:
ostream&
를 반환함으로써 연속된 출력 연산을 할 수 있습니다.- 예를 들어,
cout << p1 << p2;
와 같이 여러 객체를 연속적으로 출력할 수 있습니다.
- 스트림 상태 유지:
- 반환된
ostream&
는 스트림의 상태(예: 실패 플래그)를 유지합니다. - 출력 중에 오류가 발생하면, 반환된 스트림 객체에 오류 상태가 설정되어 이후의 출력 연산에 영향을 미칩니다.
- 반환된
- 연산자 체이닝:
ostream&
를 반환함으로써, 다른 연산자와의 체이닝을 가능하게 합니다.- 예를 들어,
cout << p1 << ", " << p2
와 같이 하나의 출력 스트림으로 여러 객체를 연속적으로 출력할 수 있습니다.
예시 코드의 재사용 가능성
연속적인 입출력 예시를 통해 반환된 istream&
와 ostream&
가 어떻게 사용되는지 보여드리겠습니다.
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string name;
int age;
public:
Person() : name(""), age(0) {}
Person(string name, int age) : name(name), age(age) {}
// >> 연산자 오버로딩 (입력)
friend istream& operator>>(istream& is, Person& person) {
cout << "Enter name: ";
is >> person.name;
cout << "Enter age: ";
is >> person.age;
return is;
}
// << 연산자 오버로딩 (출력)
friend ostream& operator<<(ostream& os, const Person& person) {
os << "Name: " << person.name << ", Age: " << person.age;
return os;
}
};
int main() {
Person p1, p2;
// 연속적인 입력
cin >> p1 >> p2;
// 연속적인 출력
cout << p1 << endl << p2 << endl;
return 0;
}
스트림 연산자 우선순위
cin >> p1 >> p2;
구문에서 cin >> p1
이 먼저 동작합니다. 이는 연산자 오버로딩과 연산자 우선순위 및 결합 규칙에 따라 결정됩니다.
연산자 우선순위와 결합 규칙
- 연산자 우선순위:
>>
연산자는 왼쪽에서 오른쪽으로 결합합니다.- 따라서, 가장 왼쪽의
cin >> p1
이 먼저 평가됩니다.
- 연산자 오버로딩:
cin >> p1
이 평가될 때,operator>>(cin, p1)
이 호출됩니다.- 이 연산자는
istream&
를 반환하므로,cin
스트림을 반환합니다.
- 연속적인 평가:
- 반환된
istream&
에 대해 다음 연산>> p2
가 적용됩니다. - 즉,
cin >> p1
이 평가된 후, 반환된 스트림 객체에 대해>> p2
가 평가됩니다.
- 반환된
예시를 통해 설명
다음은 Person
클래스에 대해 >>
연산자 오버로딩을 사용한 예제입니다.
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string name;
int age;
public:
Person() : name(""), age(0) {}
Person(string name, int age) : name(name), age(age) {}
// >> 연산자 오버로딩 (입력)
friend istream& operator>>(istream& is, Person& person) {
cout << "Enter name: ";
is >> person.name;
cout << "Enter age: ";
is >> person.age;
return is;
}
// << 연산자 오버로딩 (출력)
friend ostream& operator<<(ostream& os, const Person& person) {
os << "Name: " << person.name << ", Age: " << person.age;
return os;
}
};
int main() {
Person p1, p2;
// 연속적인 입력
cin >> p1 >> p2;
// 연속적인 출력
cout << p1 << endl << p2 << endl;
return 0;
}
동작 순서
- 첫 번째 평가:
cin >> p1
operator>>(cin, p1)
가 호출됩니다.- 사용자로부터 이름과 나이를 입력받아
p1
객체에 저장합니다. - 반환값으로
cin
스트림 객체가 반환됩니다.
- 두 번째 평가:
cin >> p2
- 첫 번째 평가의 반환값인
cin
스트림 객체에 대해operator>>(cin, p2)
가 호출됩니다. - 사용자로부터 이름과 나이를 입력받아
p2
객체에 저장합니다.
- 첫 번째 평가의 반환값인
결과적으로, cin >> p1 >> p2;
구문은 다음과 같이 동작합니다:
cin >> p1
을 먼저 평가하여p1
에 데이터를 입력받습니다.- 그 결과로 반환된
cin
스트림 객체에 대해>> p2
를 평가하여p2
에 데이터를 입력받습니다.
요약
cin >> p1 >> p2;
에서 cin >> p1
이 먼저 동작하고, 그 다음에 p1
에 대한 입력이 완료된 후에 cin >> p2
가 동작합니다. 이를 통해 연속적인 입력이 가능합니다.
'Programming Language > C++' 카테고리의 다른 글
[C++] std::distance, std::advance (0) | 2024.07.01 |
---|---|
[Modern C++] std::move, std::forward (0) | 2024.06.30 |
[C++] 클래스와 함수의 friend 선언 (0) | 2024.06.29 |
[C++] 스마트 포인터 (0) | 2024.06.28 |
[Modern C++] 함수 객체와 람다식 (0) | 2024.06.28 |