[Basic C++] #28_static 키워드
C++ 개발에서 까다로운 문법 혹은 특별한 의미를 갖는 부분에 대해 알아보겠습니다.
"전문가를 위한 C"의 10 항목, "C++의 까다롭고 유별난 부분들"에 해당하는 내용입니다.
Overview
- 개념
- 클래스와 static
- 링킹
- namespace
#0. 개념
1. static 키워드?
- staic 키워드의 의미는 문맥에 따라서 달라집니다. 일반적으로, static 키워드는 변수 혹은 함수를 내부 링킹을 통해 정의하기 위해 사용됩니다. 더불어, static으로 정의한 변수 혹은 함수는 메모리 구조의 Data 영역에 저장되어 프로그램의 시작과 함께 메모리가 할당되며, 프로그램의 종료 시점에 해제됩니다.
- static 키워드는 어떤 함수 내 static 변수, 어떤 클래스 내 static 데이터 멤버, 그리고 static 멤버 메서드에 사용됩니다.
#1. 클래스와 static
1. static 데이터 멤버, stataic 메서드
- 클래스의 데이터 멤버 혹은 멤버 함수를 "static"으로 선언할 수 있습니다.
- static 데이터 멤버의 경우, 객체별로 따로 존재하지 않고, 모든 객체에 공통으로 속하는 하나의 데이터만 존재합니다. 예를 들면, Animal 클래스를 통해 생성한 원숭이 객체와 펭귄 객체는 각각 운동 능력, 먹는 음식 등 다양한 속성 등을 별도로 수정 가능하지만, 동물인지, 혹은 사람인지에 대한 여부는 클래스 수준에서 static 데이터 멤버를 통해 공통으로 속하는 단 하나의 데이터 멤버로 존재합니다(정확하지 않지만, 쉬운 이해를 위해 억지를...ㅎㅎ).
- static 멤버 함수도 이와 동일하게 특정 객체에 종속되어 호출되지 않고, 클래스 수준에서 존재합니다.
2. staitc 데이터 멤버의 초기화
class Locator
{
public:
static void Register(Interface* _service) { service = _service; }
static Interface* Provide() { return service; }
private:
static Interface* service;
};
// static 데이터 멤버는 외부에서 초기화 해주어야 에러가 발생하지 않습니다!
Interface* Locator::service = nullptr;
Details
- static 데이터 멤버는 동일한 파일 유효 범위 내 클래스 정의 밖에서 초기화해주어야 그 효율성을 가집니다. 왜냐하면, 생성자에서 static 데이터 멤버를 초기화 할 경우, 해당 클래스 객체들은 클래스의 데이터 멤버들의 복사본을 가지며, 각 객체의 생성 시점에 생성자가 매번 호출되기 때문이죠.
#2. 링킹
1. 개념
- static 키워드의 활용에대해 자세하기 알아보기 전에 먼저 링킹에 대한 이해가 필요합니다.
- C++ 소스파일이 컴파일되면, 소스별로 독립적인 obj 파일이 생성됩니다.
- 이 obj 파일들을 하나로 연결함으로서 bin 파일이 만들어집니다.
- 이때, 함수나 변수들의 이름을 기준으로 obj 파일에서 일어나는 변수 참조 혹은 함수 호출이 서로 연결되는데, 같은 소스 안에서 연결되는 경우를 static 링킹(내부 링킹), 외부 소스와 연결되는 경우를 extern 링킹(외부 링킹)이라고 합니다.
- 기본적으로 전역 변수나 함수는 외부 링킹이 적용됩니다.
- 이 과정에서 static 키워드를 통해 내부 링킹이 적용될 수 있도록 강제하는 것이죠.
2. 내부 링킹 코드 예제
// AnotherFile.cpp
#include <iostream>
using namespace std;
void f(); // 일반 선언
void f()
{
cout << "f is called'\n'" << endl;
}
static void f2(); // static 선언
void f2()
{
cout << "f2 is called'\n'" << endl;
}
/***********************************************/
// FirstFile.cpp
void f();
int main()
{
f(); // Ok!!
f2(); // Error!!
return;
}
Details
- 위 코드에서 "f()" 함수 호출은 아무런 문제가 없습니다,
- 왜냐하면 "FirstFile.cpp"에서 호출하는 "f()" 함수는 외부 링크를 통해 다른 소스파일에서 찾기 때문입니다.
- 반면에, "f2()" 함수의 호출은 문제가 발생합니다.
- 함수의 프로토타입 선언 시 "static" 키워드를 통해 내부 링킹을 강제했기 때문입니다.
- 따라서, "AnotherFile.cpp"에 선언한 "f2()" 함수의 프로토타입을 "FirstFile.cpp"에서는 찾을 수 없게됩니다.
3. 외부 링킹 코드 예제
extern int x;
int x = 3;
Details
- "extern" 키워드는 "static"과 반대로 명시적으로 외부 링킹 할 대상을 선언합니다.
- "extern" 키워드는 전역 변수보다 더 넓은 접근성을 제공하고, 정의된 변수를 참조하는 외부 파일에서 유용하게 사용됩니다,
- 왜냐하면 "extern" 키워드는 모든 소스파일에서 전역적으로 변수에 접근할 수 있도록 해주기 때문입니다.
#3. namespace
1. static의 대안 namespace
#include <iostream>
using namespace std;
namespace {
void F2();
void F2()
{
cout << "F2 is called\n" << endl;
}
}
Details
- "static" 키워드 사용의 대안으로 무명 네임스페이스(namespace) 사용을 고려해볼 수 있습니다.
- 네임스페이스 블록 안에 있는 코드는 내부 링킹이 강제되어 같은 소스파일의 코드는 서로 이용 가능하지만,
- 외부 소스 파일에서는 접근할 수 없습니다.
'언어 > Basic C++' 카테고리의 다른 글
[Basic C++] #29_Set, STL 컨테이너 (0) | 2022.11.19 |
---|---|
[Basic C++] #22_참조형 변수 (0) | 2022.10.12 |
[Basic C++] #61_객체 풀, Obejct Pooling (0) | 2022.10.07 |
[Basic C++] #60_스마트 포인터 (0) | 2022.09.28 |
[Basic C++] #59_가비지 컬렉션 (1) | 2022.09.27 |