cout 원리
cout 은 ostream 타입의 객체이다.
모든 primitive 타입에 대해서 operator << 연산자 함수가 구현되어 있다.
cout << 3 ==> cout.operator<<(int)
cout << 3.4 ==> cout.operator<<(double)
#include <iostream>
using namespace std;
int main()
{
printf("%d\n", 3); // 함수
cout << 3; // cout.operator<<(3) => operator<<(int)
cout << endl;
cout << 3.4; // cout.operator<<(3.4)
cout << endl;
cout.operator<<(3);
cout << endl;
cout.operator<<(3.4);
}
cout 원리 이해를 위한 ostream 클래스 정의
아래와 같이 간단하게 std::cout 연산자 재정의를 해볼 수 있다.
#include <cstdio>
namespace std
{
class ostream
{
public:
ostream& operator<<(int n) { printf("%d", n); return *this;}
ostream& operator<<(double d)
{
printf("%f", d);
return *this;
}
};
ostream cout;
}
int main()
{
std::cout << 3; // cout.operator<<(3)
std::cout << 3.4;
std::cout << 3 << 3.4;
}
ostream과 c++ 표준
1998년 표준화 이전에는 ostream 클래스
유니코드 등의 문자열 출력 불가
1998년 표준화 이후
basic_ostream<> 클래스 탬플릿
유니코드 등의 문자열 출력 가능
/*
// 1998년 C++이 표준화 되기 이전에 사용하던 클래스
class ostream
{
//...
};
// 1998년 표준화 이후 -- 코드가 복잡해졌지만 다양한 형태를 처리해줌.
template<typename T, typename Tratis = char_traits<T>>
class basic_ostream
{
};
typedef basic_ostream<char> ostream;
typedef basic_ostream<wchar_t> wostream;
ostream cout;
wostream wcout;
*/
#include <iostream>
int main()
{
std::cout << "hello";
std::wcout << L"hello"; //L은 유니코드를 의미함. 그래서 wcout를 사용해야 함.
}
사용자 정의 타입과 cout
cout의 특징
다양한 타입의 값을 출력할 때 서식 문자열(%d, %f ... ) 전달할 필요가 없다.
operator<< 함수가 다양한 타입에 대해서 오버로딩 되어 있다.
cout.operator<<(int)
cout.operator<<(double)
#include <iostream>
class Point
{
int x;
int y;
public:
Point(int a = 0, int b = 0) : x(a), y(b) {}
};
int main()
{
int n = 0;
double d = 3.4;
std::cout << n; // cout.operator<<(int)
std::cout << d; // cout.operator<<(double)
Point pt(1,2);
std::cout << pt; // cout.operator<<(Point)
// operator<<(cout, pt)
// operator<<(ostream, Point)
}
아래와 같이 에러가 발생된다.
main.cpp:20:15: error: no match for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream’} and ‘Point’)
20 | std::cout << pt; // cout.operator<<(Point)
| ~~~~~~~~~ ^~ ~~
| | |
| | Point
| std::ostream {aka std::basic_ostream<char>}
In file included from /usr/include/c++/9/iostream:39,
from main.cpp:1:
/usr/include/c++/9/ostream:108:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream]’
108 | operator<<(__ostream_type& (*__pf)(__ostream_type&))
| ^~~~~~~~
사용자 정의 타입을 cout으로 출력할 수 있게 하려면
operator<< 연산자 함수를 멤버가 아닌 일반 함수로 제공한다.
private 멤버에 접근하기 위해서는 friend 함수로 선언한다.
#include <iostream>
class Point
{
int x;
int y;
public:
Point(int a = 0, int b = 0) : x(a), y(b) {}
friend std::ostream&
operator<<(std::ostream& os, const Point& pt);
};
//std::ostream& operator<<(const std::ostream& os, const Point& pt)
// const 있어면 에러 주의
// const의 경우 상수 함수 호출이 가능한데 const에 의해
// os.operator<<(pt.x) 호출시 문제가 된다. 그래서 const 넣어주면 안된다.
std::ostream& operator<<(std::ostream& os, const Point& pt)
{
os << pt.x << ", " << pt.y;
return os;
}
int main()
{
Point pt(1,2);
std::cout << pt << std::endl; // operator<<(cout, pt)
}
cout과 endl
std::cout은 객체 이므로 다양한 멤버 함수가 있다.
endl 역시 함수이다.
인자로 cout을 전달받아서 개행 문자를 출력하고 출력 버퍼를 비우고 cout을 반환함.
#include <iostream>
using namespace std;
int main()
{
cout << endl;
cout.put('\n');
cout.flush();
}
endl이 함수이기 때문에 아래와 같이 다양한 방식으로 사용이 가능하다.
#include <iostream>
using namespace std;
ostream& myendl( ostream& os)
{
os.put('\n');
os.flush();
return os;
}
int main()
{
cout << endl << "A";
endl(cout) << "B";
myendl(cout) << "C";
cout << endl; // cout.operator<<(endl)
// cout.operator<<(함수포인터)
cout << myendl;
cout << "------------------" <<endl;
}
'C++' 카테고리의 다른 글
[C++] Design Patterns (디자인 패턴) - GoF (0) | 2022.01.26 |
---|---|
[C++] exception (예외처리) (0) | 2022.01.10 |
[C++] 연산자 재정의 (operator overloading) (0) | 2022.01.01 |
[C++] 다중 상속 (multiple inheritance) (0) | 2021.12.31 |
[C++] 상속과 RTTI (0) | 2021.12.30 |
댓글