- 정적 멤버 함수
이전에 우리는 클래스 내부에 구현해 놓은 기능에 접근하기 위해 범위 지정 연산자(::)를 사용해야 했다.
물론 멤버 함수의 경우에는 결국 객체가 필요하기 때문에 직접 접근해서 호출해 볼 순 없었지만
멤버 함수 중에는 정적 멤버 함수라는 것이 존재한다.
이런 정적 멤버의 특징은 멤버 함수이면서도 객체 없이 호출할 수 있다는 점이다.
정적 멤버 함수는 자료형 앞에 static 키워드를 붙여 선언할 수 있다.
class CTest
{
private:
int m_i;
public:
// 객체 없이 호출 가능
static void MemberFunc()
{
}
};
int main()
{
CList<float> list;
for (int i = 0; i < 4; ++i)
{
list.push_back(i);
}
// 정적 멤버 함수를 호출하고 싶을 때에는 해당 클래스 안에 선언되어 있는 함수를
// 객체를 할당하지 않고도 사용할 수 있다.
CTest::MemberFunc();
return 0;
}
- 네임스페이스(namespace)
네임스페이스는 말 그대로 이름 공간이다.
사용자가 원하는 이름을 입력하면 그 이름 안에 있는 요소들이 하나의 공간 안에 존재하게 된다.
특이한 점은 이렇게 네임스페이스가 붙은 요소를 외부에서 접근하기 위해서는 반드시 네임스페이스를
호출한 객체 앞에 붙여주어야 한다는 점이다.
namespace MYSPACE
{
int g_int;
}
아래의 경우처럼 네임스페이스를 명시하지 않고 그냥 요소를 입력하면 인식되지 않는다.
g_int = 0;
올바른 접근 방법은 객체 앞에 네임스페이스를 명시해 주는 것이다.
흔히 사용되는, 사용자의 입력을 받는 cin 함수를 호출할 때 std::cin >> iInput;처럼 앞에 std::를 붙여주는 것과 동일하다.
MYSPACE::g_int = 0;
- 왜 네임스페이스를 명시해야 할까?
바로 라이브러리를 사용하는 사용자가 동일한 이름의 변수를 만들 수도 있기 때문이다. 이 경우 각 변수에 대한 구별이 정확히 되지 않기 때문에 문제가 발생할 수 있다.
이런 특징으로 인해 네임스페이스가 다르면 아래의 경우처럼 동일한 이름의 변수를 선언할 수 있게 된다.
namespace MYSPACE
{
int g_int;
}
namespace OTHERSPACE
{
int g_int;
}
하지만 현재 작업 중인 프로그램에서 중복된 이름이 존재하지 않는 변수까지 네임스페이스로 묶여버리면 중복 변수 간의 구분이 필요 없는데도 이 변수를 호출할 때마다 네임스페이스를 명시해주어야 하는 불편함이 발생한다.
이런 경우를 위해서 네임스페이스를 모두 해제하는 것이 아니라 특정 기능만 해제할 수 있는 기능이 존재한다.
using std::cout;
using std::endl;
using 키워드를 사용하면 함께 명시한 네임스페이스를 사용할 수 있도록 해준다.
이때 네임스페이스::해제할 기능을 선언하면 해당 네임스페이스에서 특정 기능만 해제하여
네임스페이스 명시 없이도 사용할 수 있게 된다.
cout << "안녕" << 10 << endl;
그런데 어떻게 이게 가능한 걸까? cout의 정의를 따라가보면 다음과 같이 ostream이라는 클래스로 만든 cout 객체가 외부 변수로 선언되어 있음을 확인할 수 있다.
이전에 배웠듯 외부 변수는 메모리 영역에 모든 곳에서 사용이 가능한 변수를 저장함으로써 프로그램 실행 중이라면 언제든지 원할 때마다 호출 할 수 있도록 하기 위해서 사용한다.
이때 << 역시 이전에 배웠던 연산자 오버로딩으로 구현된 것이다.
이번에는 직접 cout과 비슷한 기능을 하는 함수를 만들어 보자.
일반적인 cout 함수의 작동 결과를 생각해보면 숫자나 문자를 출력한다는 것을 알 수 있다.
이를 위해 각 자료형에 맞춘 인자를 가지도록 연산자를 오버로딩 해본다.
class CMyOStream
{
public:
CMyOStream& operator << (int _idata)
// _idata에는 호출시 사용자가 입력한 정수 값이 들어온다.
{
wprintf(L"%d", _idata);
return *this; // 호출시 이 this에는 mycout의 주소가 들어온다.
}
CMyOStream& operator << (const wchar_t* _pString)
{
wprintf(L"%s", _pString);
return *this;
}
};
CMyOStream mycout; // 1바이트 크기를 가짐
int main()
{
//////// 비주얼스튜디오 언어 설정
setlocale(LC_ALL, "korean"); // 출력 언어를 한글로 고정
_wsetlocale(LC_ALL, L"korean");
mycout << L"한글";
return 0;
}
이어서 endl 를 구현해보자. 이 endl역시 일종의 함수이다.
아래는 전체 코드이다.
#include <iostream>
#include "CList.h"
void MyEndL()
{
wprintf(L"\n");
}
class CTest
{
private:
int m_i;
public:
// 객체 없이 호출 가능
static void MemberFunc()
{
}
};
class CMyOStream
{
public:
CMyOStream& operator << (int _idata)
// _idata에는 호출시 사용자가 입력한 정수 값이 들어온다.
{
wprintf(L"%d", _idata);
return *this; // 호출시 이 this에는 mycout의 주소가 들어온다.
}
CMyOStream& operator << (const wchar_t* _pString)
{
wprintf(L"%s", _pString);
return *this;
}
CMyOStream& operator << (void(*_pFunc)(void))
{
_pFunc();
return *this;
}
CMyOStream& operator >> (int& _idata)
{
scanf_s("%d", &_idata);
return *this;
}
};
CMyOStream mycout; // 1바이트 크기를 가짐
int main()
{
CList<float> list;
for (int i = 0; i < 4; ++i)
{
list.push_back(i);
}
// 정적 멤버 함수를 호출하고 싶을 때에는 해당 클래스 안에 선언되어 있는 함수를
// 객체를 할당하지 않고도 사용할 수 있다.
CTest::MemberFunc();
//////// 비주얼스튜디오 언어 설정
setlocale(LC_ALL, "korean"); // 출력 언어를 한글로 고정
_wsetlocale(LC_ALL, L"korean");
mycout << L"한글";
//int a = 0;
// mycout >> a;
mycout << MyEndL; // 참조 안에서 전달해준 주소를 받아서 그걸 MyEndL에서 호출해준다.
mycout << 10 << L" " << 20 << L" " << L"문장" << MyEndL;
return 0;
}
'C,C++' 카테고리의 다른 글
[C++] iterator (0) | 2023.02.05 |
---|---|
[C++] STL(vector, list) (0) | 2023.02.03 |
함수 템플릿, 클래스 템플릿, 클래스 템플릿 리스트 (0) | 2023.01.31 |
클래스를 이용한 배열 (0) | 2023.01.31 |
클래스 (0) | 2023.01.28 |