728x90
다음은 C++의 콘솔 입출력에 사용되는 cout과 endl의 이해를 돕기 위한 예제이다.
#include <iostream>
namespace mystd { //cout과 endl을 직접 구현하기 위해 선언한 이름공간
using namespace std;//이 지역 내에서만 유효한 선언
class ostream {
public:
//<<dustkswk dhqjfheld
void operator<<(const char* str) {
printf("%s", str);
}
void operator<<(char str) {
printf("%c", str);
}
void operator<<(int num) {
printf("%d", num);
}
void operator<<(double e) {
printf("%g", e);
}
void operator<< (ostream& (*fp)(ostream& ostream)) {
fp(*this);
}
};
ostream& endl(ostream& ostm) {
ostm << '\n';
fflush(stdout);//버퍼 비우기
return ostm;
}
ostream cout;
}
int main(void) {
using mystd::cout;//mystd내에 선언된 cout과 endl 사용
using mystd::endl;
cout << "Simple String"; //cout.operator<<("Simple String");
cout << endl;//cout.operator<<(endl);
cout << 3.14;//cout.operator<<(3.14);
cout << endl;//cout.operator<<(endl);
cout << 123;//cout.operator<<(123);
endl(cout);
return 0;
}
위의 예제는 한가지 문제점을 지니고 있다.
- cout<<123<<endl<<3.14<<endl;
이러한 형태의 문장은 컴파일 오류를 발생시킨다.
<<연산자는 왼쪽에서 오른쪽으로 진행이 된다. 따라서 위의 문장은 다음과 같은 순서로 연산이 이루어진다.
- ( ( ( cout << (123) << endl ) << 3.14 ) << endl );
즉, 모든 <<연산의 결과로는 cout이 반환되어야 한다.
그래야 연이은 <<연산을 진행할 수 있다.
그러나 앞의 예제의 <<연산자는 cout을 반환하지 않아서 컴파일 에러가 발생한 것이다.
앞서 보인 예제를 확장해보자.
#include <iostream>
namespace mystd {
using namespace std;
class ostream {
//cout 객체의 참조값을 반환하는 형태로 확장
public:
ostream& operator<< (char* str)
{
printf("%s", str);
return *this;
}
ostream& operator<< (char str)
{
printf("%c", str);
return *this;
}
ostream& operator<<(int num) {
printf("%d", num);
return *this;
}
ostream& operator<<(double e) {
printf("%g", e);
return *this;
}
ostream& operator<<(ostream& (*fp)(ostream& ostm)) {
return fp(*this);
}
};
//endl함수는 인자로 전달된 객체의 참조값을 반환하므로,
//반환된 값을 재 반환하는 형태로 연산자를 오버로딩
ostream& endl(ostream& ostm) {
ostm << '\n';
fflush(stdout);
return ostm;
}
ostream cout;
}
int main(void) {
using mystd::cout;
using mystd::endl;
cout << 3.14 << endl << 123 << endl;
return 0;
}
<<,>> 연산자의 오버로딩
이번에는 앞서 정의한 Point 클래스를 대상으로 <<연산자와 >>연산자를 오버로딩 해 보고자 한다.
- cout은 ostream 클래스의 객체이다.
- ostream은 이름공간 std 안에 선언되어 있으며, 이의 사용을 위해서는 헤더파일 <iostream>을 포함해야한다.
#include <iostream>
using namespace std;
class Point {
private:
int xpos, ypos;
public:
Point(int x = 0, int y = 0) : xpos(x), ypos(y)
{ }
void ShowPosition() const {
cout << '[' << xpos << ", " << ypos << ']' << endl;
}
friend ostream& operator << (ostream&, const Point&);
};
ostream& operator<<(ostream& os, const Point& pos) {
//인자로 전달된 cout의 참조자를 통한 출력을 구성
os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl;
return os;
}
int main(void) {
Point pos1(1, 3);
cout << pos1;
Point pos2(101, 303);
cout << pos2;
return 0;
}
이번에는 Point 클래스를 대상으로 한 >> 연산자의 오버로딩을 구현해보자.
- cin은 istream 클래스의 객체이다.
- istream은 이름공간 std 안에 선언되어 있으며, 이의 사용을 위해서는 헤더 파일 <iostream>을 포함해야 한다.
/* 문제 10-3
* main 함수가 보이는 대로 데이터의 입력이 가능하도록,
* 그리고 실행의 예에서 보이는 대로 출력이 이뤄지도록
* >>연산자를 오버로딩하자.
*/
#include <iostream>
using namespace std;
class Point {
private:
int xpos, ypos;
public:
Point(int x = 0, int y = 0) : xpos(x), ypos(y)
{ }
void ShowPosition() const {
cout << '[' << xpos << ", " << ypos << ']' << endl;
}
friend ostream& operator<<(ostream&, const Point&);
friend istream& operator>>(istream&, Point& pos);
};
ostream& operator<<(ostream& os, const Point& pos) {
//인자로 전달된 cout의 참조자를 통한 출력을 구성
os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl;
return os;
}
istream& operator>>(istream& is, Point& pos) {
//인자로 전달된 cout의 참조자를 통한 출력을 구성
is >> pos.xpos >> pos.ypos;
return is;
}
int main(void) {
Point pos1;
cout << "x, y 좌표 순으로 입력: ";
cin >> pos1;
cout << pos1;
Point pos2;
cout << "x, y 좌표 순으로 입력: ";
cin >> pos2;
cout << pos2;
return 0;
}
728x90
'공부 > C++' 카테고리의 다른 글
[C++] 11-1. 반드시 해야 하는 대입 연산자의 오버로딩 (0) | 2024.11.27 |
---|---|
[C++] 10-3. 교환법칙 문제의 해결 (0) | 2024.11.27 |
[C++] 10-2. 단항 연산자의 오버로딩 (0) | 2024.11.25 |
[C++] 10-1. 연산자 오버로딩의 이해와 유형 (0) | 2024.11.25 |
[C++] 9-2. 다중상속(Multiple Inheritance)에 대한 이해 (0) | 2024.11.22 |