[C++] 입출력 시스템

    C++에 포맷 입출력은 3가지 방법이 존재한다.

    1. 포맷 플래그

    2. 포맷 함수

    3. 조작자

     

    포맷 플래그

    ios 클래스에는 포맷 플래그 값을 가진 멤버 변수가 있다.

    이 멤버 변수를 이용하여 입출력의 포맷을 수정할 수 있다.

    포맷 플래그 값을 가진 멤버 변수를 수정하기 위해서는, set과 unset 메서드를 사용해야 한다.

     

    #include <iostream>
    using namespace std;
    
    int main() {
    	cout << 30 << endl;
    
    	cout.unsetf(ios::dec);
    	cout.setf(ios::hex);
    	cout << 30 << endl;
    
    	cout.setf(ios::showbase);
    	cout << 30 << endl;
    
    	cout.setf(ios::uppercase);
    	cout << 30 << endl;
    
    	cout.setf(ios::dec | ios::showpoint);
    
    	cout << 23.5 << endl;
    
    	cout.setf(ios::scientific);
    	cout << 23.5 << endl;
    
    	cout.setf(ios::showpos);
    	cout << 23.5 << endl;
    }
    30
    1e
    0x1e
    0X1E
    23.5000
    2.350000E+01
    +2.350000E+01

     

     

    포맷 함수 활용

    cout. 으로 시작하는 포맷 함수를 사용하는 방법으로도 입출력 포맷을 지정할 수 있다.

    포맷 플래그를 이용한 방법과 달리, 각 포맷 지정 함수의 이름이 정해져 있다. 

    각 함수를 호출해서 포맷을 지정하는 방법.

    cout.width(int) , cout.fill(char) , int precision(int)...

    #include <iostream>
    using namespace std;
    
    void showWidth() {
    	cout.width(10);
    	cout << "Hello" << endl;;
    	cout.width(5);
    	cout << 12 << endl;
    
    	cout << '%';
    	cout.width(10); //다음에 출력되는 korea/만 10칸으로 지정.
    	cout << "Korea/" << "Seoul/" << "City" << endl;
    }
    
    int main() {
    	showWidth();
    	cout << endl;
    
    	cout.fill('^');
    	showWidth();
    	cout << endl;
    
    	cout.precision(5);
    	cout << 11. / 3. << endl;
    
    }
         Hello
       12
    %    Korea/Seoul/City
    
    ^^^^^Hello
    ^^^12
    %^^^^Korea/Seoul/City
    
    3.6667

    cout.width(int) : 다음에 출력되는 '한개'의 크기(칸) 지정 

    cout.fill(char) : 공백을 매개변수 문자로 채움

    cout.precision(int) : 유효숫자 자리 수 지정

     

    조작자 (manipulator)

    manipulator, stream manipultator.

    조작자란 함수로, 항상 << 또는 >> 연산자와 함께 사용한다. 개발자는 C++ 표준 라이브러리에서 제공하는 조작자를 사용할 수도 있고, 개발자만의 조작자를 작성하여 사용할수도 있다. 조작자는 크게 매개변수가 있는 것과 없는 것으로 구분된다.

    int main() {
    	cout << hex << showbase << 30 << endl;
    	cout << dec << showpos << 100 << endl;
    	cout << true << ' ' << false << endl;
    	cout << boolalpha << true << ' ' << false << endl;
    }
    0x1e
    +100
    +1 +0
    true false

    'endl'도 매개변수 없는 조작자 중 하나이다.

     

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main() {
    	cout << showbase;
    
    	cout << setw(8) << "Number";
    	cout << setw(10) << "Octa";
    	cout << setw(10) << "Hexa" << endl;
    
    	for (int i = 0; i < 50; i += 5) {
    		cout << setw(8) << setfill('.') << dec << i;
    		cout << setw(10) << setfill(' ') << oct << i;
    		cout << setw(10) << setfill(' ') << hex << i << endl;
    	}
    }
      Number      Octa      Hexa
    .......0         0         0
    .......5        05       0x5
    ......10       012       0xa
    ......15       017       0xf
    ......20       024      0x14
    ......25       031      0x19
    ......30       036      0x1e
    ......35       043      0x23
    ......40       050      0x28
    ......45       055      0x2d

    위와 같이 매개변수가 있는 조작자를 사용하려면 <iomanip> 라이브러리가 필요하다.

     

     

    삽입 연산자(Insertion Operator) , <<

    본래 "<<" 연산자는 C++의 기본 연산자, 정수 시프트 연산자로 정의되어 있음.

    ostream 클래스에서 연산자 재정의를 통해 삽입 연산자로 더 많이 사용된다.

    유저는 사용자 삽입 연산자를 정의해서 스스로가 작성한 클래스의 객체를 << 연산자로 출력되도록 만들수있다.

    #include <iostream>
    using namespace std;
    
    class Point {
    	int x, y;
    public:
    	Point(int x = 0, int y = 0) {
    		this->x = x;
    		this->y = y;
    	}
    	friend ostream& operator << (ostream& stream, Point a);
    };
    
    ostream& operator << (ostream& stream, Point a) {
    	stream << "(" << a.x << "," << a.y << ")";
    	return stream;
    }
    
    int main() {
    	Point p(3, 4);
    	cout << p << endl;
    
    	Point q(1, 100), r(2, 200);
    	cout << q << r << endl;
    }
    (3,4)
    (1,100)(2,200)

    스트림 삽입 연산자를 사용자가 정의할 때, 주의해야 할 점은 첫번째로, 객체의 private 변수에 접근하기 위해 friend 함수로 작성해야 하고, 두번째로 ostream(출력 스트림)을 매개변수로 받아 스트림에 출력 내용을 저장하고 ostream을 다시 리턴해줘야 한다는 것이다. 

     

    추출 연산자(Extraction Operator) , >>

    마찬가지로 정수 시프트 연산자로 정의된 것을 istream 클래스에서 재정의해서 사용한다.

    #include <iostream>
    using namespace std;
    
    class Point {
    	int x, y;
    public:
    	Point(int x = 0, int y = 0) {
    		this->x = x;
    		this->y = y;
    	}
    	friend ostream& operator << (ostream& stream, Point a);
    	friend istream& operator >> (istream& ist, Point& a);
    };
    
    ostream& operator << (ostream& stream, Point a) {
    	stream << "(" << a.x << "," << a.y << ")";
    	return stream;
    }
    
    istream& operator >> (istream& ist, Point& a) {
    	cout << "X 좌표 : ";
    	ist >> a.x;
    	cout << "Y 좌표 : ";
    	ist >> a.y;
    	return ist;
    }
    
    int main() {
    	Point p(3, 4);
    	cout << p << endl;
    
    	Point q(1, 100), r(2, 200);
    	cout << q << r << endl;
    
    	Point c;
    	cin >> c;
    	cout << c;
    }
    (3,4)
    (1,100)(2,200)
    X 좌표 : 100
    Y 좌표 : 200
    (100,200)

    객체의 private 멤버변수에 접근하기 위해 friend함수로 선언하는 것 외에 주의할 점은, 데이터를 수정할 Point 객체를 참조형(&)으로 받아야한다는 것이다. 지난 값에의한 호출, 참조에의한 호출을 설명한 포스팅에서 말했 듯, 값을 변경하기 위해서는 call by reference를 사용하는 것이 바람직하다.

     

    사용자 정의 조작자

    조작자 역시 사용자가 정의하여 사용할 수 있다.

    #include <iostream>
    using namespace std;
    
    ostream& fivestar(ostream& outs) {
    	return outs << "*****";
    }
    
    ostream& rightarrow(ostream& outs) {
    	return outs << "---->";
    }
    
    ostream& beep(ostream& outs) {
    	return outs << '\a';
    }
    
    int main() {
    	cout << "벨이 울립니다." << beep << endl;
    	cout << "C" << rightarrow << "C++" << rightarrow << "JAVA" << endl;
    	cout << "Visual" << fivestar << "C++" << endl;
    }
    벨이 울립니다.
    C---->C++---->JAVA
    Visual*****C++

    ostream의 조작자를 정의해서 사용한다. main함수 1라인의 beep 조작자는 시스템의 소리를 발생시킨다.

     

    #include <iostream>
    #include <string>
    using namespace std;
    
    istream& question(istream& ins) {
    	cout << "거울아 거울아 누가 제일 예쁘니?";
    	return ins;
    }
    
    int main() {
    	string answer;
    	cin >> question >> answer;
    	cout << "세상에서 제일 예쁜 사람은 " << answer << "입니다." << endl;
    }
    거울아 거울아 누가 제일 예쁘니? //백설공주 입력
    세상에서 제일 예쁜 사람은 백설공주입니다.

    istream을 참조 매개변수로 받아 참조형으로 리턴해준다.

     

     

    참고로 조작자 endl은 다음과 같은 실행 과정을 겪는다. 

     

    댓글