728x90
황기태 저자의 명품 C++ Programming 개정판을 읽고 학습한 내용을 정리한 포스트입니다!
https://search.shopping.naver.com/book/catalog/32436115747
삽입 연산자의 중복
- 출력 스트림에 데이터를 출력하는 << 연산자를 삽입 연산자(insertion operator) 혹은 삽입자라고 부른다.
- 본래 << 연산자는 정수를 비트 단위로 시프트(shift)하는 C++의 기본 연산자이다.
- 그런데 C++ 입출력 시스템은 다양한 값을 출력할 수 있도록 ostream 클래스에 << 연산자를 중복 작성하였다.
삽입 연산자의 실행 과정
cout << 'a' << 123 << endl;
- 위의 코드는 객체, 입출력 스트림, 연산자 중복, 참조 매개 변수, 참조 리턴이 절묘하게 연결되어 있는 코드이다.
리턴 타입이 의미하는 것
- ostream 클래스 내에 중복 작성된 모든 << 연산자들은 아래와 같이 ostream&를 리턴한다.
- << 연산자는 출력 스트림에 데이터를 삽입한 후, 출력 스트림(*this)을 리턴하며 리턴 타입이 ostream&이므로 스트림의 참조가 리턴된다.
- 만약 리턴 타입이 ostream이라면, 복사본(*this)이 리턴되고, 그 다음에 실행되는 << 연산은 복사된 스트림에 출력하게 되어, 연속되는 두 << 연산이 서로 다른 출력 스트림에 출력하게 된다.
ostream& operator << (char c); // 문자를 출력하는 << 연산자
구체적인 실행 과정
- 구체적인 실행 과정은 아래의 그림과 같다.
1. cout << 'a'에서 << 연산자를 호출
- 컴파일러는 위 코드를 아래와 같이 변형하여 컴파일한다.
- 이 코드는 cout 객체 내의 operator<<(char c)를 호출하고 'a'를 매개 변수에 넘겨준다.
cout . << ('a')
2. cout의 연산자 함수 ostream& operator << (char c)가 실행된다.
ostream& operator << (char c) {
... 현재 스트림 버퍼에 c('a')를 삽입한다.
... 버퍼가 차면 장치에 출력한다.
return *this; // 이 스트림의 참조를 리턴한다.
}
- operator<< (char c) 함수는 문자 'a'를 현재 스트림(cout)의 버퍼에 저장하고 꽉 차면 화면에 출력한다.
- 그리고 *this 곧 현재 스트림에 대한 참조를 리턴한다.
3. << 123을 실행한다.
- cout << 'a'의 실행 결과 cout의 버퍼에 'a'가 삽입되고 cout에 대한 참조가 리턴되었다.
- 따라서, << 123은 cout << 123을 실행하는 것과 같고, 'a'가 들어 있는 cout의 버퍼에 123을 출력하는 것이다.
ostream& operator << (int n) {
... 현재 스트림 버퍼에 n(123)을 삽입한다.
... 만일 버퍼가 차면 장치에 출력한다.
return *this;
}
- operator << (int n) 함수는 매개 변수 n에 전달된 123을 현재 스트림(cout) 버퍼에 저장한다.
- 버퍼는 "a123"으로 변경되며, 적절한 시점에 화면에 출력된다.
- 즉, << 연산자가 cout의 참조를 리턴함으로써 반복되는 << 연산자에 의해 출력되는 데이터들이 cout의 버퍼를 통하여 화면에 출력된다.
사용자 삽입 연산자( <<) 만들기
Point p(3, 4);
cout << p;
- Point 객체를 출력할 수 있는 << 연산자가 C++ 입출력 시스템에 없기 때문에 직접 << 연산자를 작성해야 한다.
- cout << p에 의해 객체 p가 출력되도록 << 연산자를 작성해보자.
- cout << p는 외부에 작성된 연산자이므로 컴파일러는 아래와 같이 변형한다.
<< (cout, p);
- 따라서, 이에 맞추어 외부 함수로 << 연산자 함수를 작성하자.
// << 연산자 함수
ostream& operator << (ostream& stream, Point a) {
stream << "(" << a.x << "," << a.y << ")";
return stream;
}
- stream 참조 매개 변수에 cout이 전달되고, a에는 객체 p가 전달된다.
- private x, y를 접근할 수 있도록 << 연산자 함수를 Point 클래스에 friend로 선언
사용자 정의 삽입 연산자 함수의 원형
- 삽입 연산자 << 의 함수 원형은 아래와 같으며 둘 다 가능하다.
- 또한, 이들 연산자 함수는 외부 함수로만 작성되어야 하며 UserClass의 private 멤버에 접근하는 경우, UserClass에 프렌드로 선언되어야 한다.
ostream& operator << (ostream& outs, UserClass obj);
ostream& operator << (sotream& outs, UserClass& obj);
추출 연산자의 중복
- cin과 함께 사용되는 >> 연산자를 추출 연산자(extraction operator)라고 부른다.
- 본래는 정수를 비트 단위로 오른쪽 시프트(shift)하는 C++의 기본 연산자이기에 istream 클래스에 중복 작성하였다.
사용자 추출 연산자(>>) 만들기
- 앞서 살펴본 삽입 연산자의 실행 과정과 흡사하므로 빠르게 살펴보자.
- Point 객체 p를 생성 후 cin >> 을 사용하여 키 입력을 받으면 컴파일 오류가 발생한다. => istream에는 Point 객체의 값을 받아들이는 >> 연산자가 없기 때문에 아래와 같이 변형하여 컴파일한다.
Point p; // 디폴트로 x=0, y=0
cin >> p; // 컴파일 오류
>> (cin, p);
- 아래와 같이 외부 함수로 만들어주면 된다.
istream& operator >> (istream& ins, Point &a) { // >> 연산자 함수
cout << "x 좌표>>";
ins >> a.x;
cout << "y 좌표>>";
ins >> a.y;
return ins;
}
- 여기서 중요한 점이 2가지 있다.
- 첫째, 두 번째 매개 변수를 참조 타입(Point& a)으로 선언하는데, 이는 원본 객체 p에 값을 쓰기 위해서이다. a를 참조 타입으로 사용하지 않으면(Point a), 키 값을 읽어 매개 변수 a에 저장하여도 원본 객체 p가 변하지 않기 때문이다.
- 둘째, 이 연산자 함수가 private 멤버 x, y를 접근하도록, Point 클래스에 friend로 선언한다.
사용자 정의 추출 연산자 함수의 원형
- cin >> 연산자의 일반적인 함수 원형을 알아보자.
istream& operator >> (istream& ins, UserClass& obj);
#include <iostream>
using namespace std;
class Point { // 한 점을 표현하는 클래스
int x, y; // private 멤버
public:
Point(int x=0, int y=0) {
this->x = x;
this->y = y;
}
friend istream& operator >> (istream& ins, Point &a); // friend 선언
friend ostream& operator << (ostream& stream, Point a); // friend 선언
};
istream& operator >> (istream& ins, Point &a) { // >> 연산자 함수
cout << "x 좌표>>";
ins >> a.x;
cout << "y 좌표>>";
ins >> a.y;
return ins;
}
ostream& operator << (ostream& stream, Point a) { // << 연산자 함수
stream << "(" << a.x << "," << a.y << ")";
return stream;
}
int main() {
Point p; // Point 객체 생성
cin >> p; // >> 연산자를 호출하여 x 좌표와 y 좌표를 키보드로 읽어 객체 p 완성
cout << p; // << 연산자를 호출하여 객체 p 출력
}
728x90
'Programming Language > C++' 카테고리의 다른 글
[C++] 예외 처리 (1) | 2023.12.27 |
---|---|
[C++] 사용자 조작자 만들기 (1) | 2023.12.21 |
[C++] 포맷 (1) | 2023.12.21 |
[C++] ostream과 istream (1) | 2023.12.20 |
[C++] 입출력 기초 (1) | 2023.12.20 |