코드 없는 프로그래밍 ( 유튜브 ) 님의 https://www.youtube.com/watch?v=oD6fKjyX5to 강의를 보고 작성한 글 입니다.
Build 의 linkage 프로세스에서 사용되는 static 이랑 다른거다.
static 은 세 가지가 있다.
1. static member function
이 처럼 static member function은 object 를 만들지 않아도 call 을 할 수 있다.
이것이 가능한 이유는 sttic member fucntion은 class Object 와 연관이 되어있지 않기 때문이다.
이것은 this 라는 키워드와 연관이 있다.
this라는 키워드는 class object 의 주소를 가리키는데 static member func 은 this 와 binding 되어 있지 않기 때문에
object 를 생성하지 않아도 call이 될 수 있는것이다.
그럼 당연하게도 object와 binding 되어 있지 않다면 class member variable 에 접근 할 수 없는데
static 함수에 member variable 인 mAge 를 사용하면 컴파일 에러가 발생한다.
그리고 마찬가지로 static 함수 안에서 non-static 멤버 함수를 call 할 수 없다.
이 와는 반대로 object 에서 staticSpeak 함수를 call 할 수 있는데 당연하게도 class 의 멤버 함수이기 때문이다.
2. static member variable
중요 : ** static member variable 은 프로그램이 실행되기 전에 초기화를 시켜줘야한다. **
이유는 아래 블로그에 자세히 소개되어 있다.
https://ansohxxn.github.io/cpp/chapter8-10/
요약하자면,
static 멤버 변수는 모든 객체가 공유해야 하고, 객체를 생성하기 전에 메모리에 존재해야된다. 때문에 전에 초기화를 해줘야한다.
또한 프로그램 전체 영역에서 메모리 유지가 되야 한다.
따라서 반드시 전역 범위에서 정의 및 초기화를 해주어야 한다.
반면에,
static variable이 멤버 변수가 아니라 전역 변수라면 static int a; 만 해도 빌드 되는데 이는 static int a; 가 자동으로 0으로 초기화되기 때문이다.
다시 돌아와서 Cat 함수를 보자.
결과에서 보듯이 Cat object 는 count 를 공유한다.
이를 이해하려면 다시 한번 중요한 메모리 구조를 보자.
count 변수는 kitty.mAge 나 nabi.mAge 처럼 objcect 에 귀속되어 있지 않고, static 공간에 따로 저장되어 있다.
* 다만 Cat:: 이라는 클래스 소속이라고 일종의 namespace가 있는 것이다. ( Cat 의 모든 object 가 공유할 수 있다. )
다시 돌아와서 위의 예시 코드에서 count 변수는 speak() 함수에서만 쓰인다.
그럼 이걸 굳이 멤버 변수로 가질 필요 없이 ,speak 함수 안에 static 변수를 선언하면 접근할 수 없는 안전한 변수가 된다.
이것이 바로 3번 static variable in a function 이다.
3. static variable in a function
아래의 내용도 꼭 보기
https://post.naver.com/viewer/postView.naver?volumeNo=10142629&memberNo=559061
# 22.07.07 추가
constant.h
main.cpp
test.cpp
위 코드들을 빌드해보면,
아래와 같은 오류가 나온다.
몇 일 동안 헷갈리는지 모르겠다ㅋㅋ ( 이래서 한번 정리할때 확실히 하고 넘어가야된다..)
main.cpp test.cpp
| |
V V
.obj .obj
까지는 잘 만들어진다. 문제될게 없다.
문제는 링킹 과정인데
int g_a (전역변수는 ) default 로 extern 이 붙는다
그렇기 때문에 test.cpp 를 컴파일 하면서 g_a가 메모리에 올라갔는데 main.cpp 를 컴파일하면서 다시한번 정의 되었다고 링킹 오류가 뜨는거다.
그럼 어떻게 해야되나? static 을 붙혀주면 된다.
static 변수는 링킹 과정에서 같은 translation unit 에서만 보이기 때문에 중복정의를 피할 수 있는것이다.
그런데 여기서 중요한 사실이 한 가지 있다.
이렇게 정의된 static int g_a는 서로 다른 주소를 가진다. 즉, 완전히 다른 변수인거다.
static 말고 const 를 붙혀보자.
이상하게도 static이 붙지 않았는데도 빌드가 된다
const 는 왜 되는 거지 ?
const 가 붙은 전역변수는 default 로 static이 붙기 때문이다.
기본적으로 비-상수(not const) 전역 변수는 외부 링크 속성을 가지고 있다. 원하는 경우 static
키워드를 통해 명시적으로 내부 링크 속성을 가지게 할 수 있다.
반대로 상수(const) 전역 변수는 내부 링크 속성을 기본으로 가진다. 원하는 경우 extern
키워드를 통해 외부 링크 속성으로 만들 수 있다.
// Uninitialized definition:
int g_x; // defines uninitialized global variable (external linkage)
static int g_x; // defines uninitialized static variable (internal linkage)
const int g_x; // not allowed: const variables must be initialized
// Forward declaration via extern keyword:
extern int g_z; // forward declaration for global variable defined elsewhere
extern const int g_z; // forward declaration for const global variable defined elsewhere
// Initialized definition:
int g_y(1); // defines initialized global variable (external linkage)
static int g_y(1); // defines initialized static variable (internal linkage)
const int g_y(1); // defines initialized static variable (internal linkage)
// Initialized definition w/extern keyword:
extern int g_w(1); // defines initialized global variable (external linkage, extern keyword is redundant in this case)
extern const int g_w(1); // defines initialized const global variable (external linkage)
출처: https://boycoding.tistory.com/167?category=1007833 [소년코딩:티스토리]
'Language & etc > C++' 카테고리의 다른 글
std::Vector push_back() vs emplace_back() (0) | 2022.07.31 |
---|---|
비트 필드 (0) | 2022.07.27 |
std::Move, perfect forwarding - ① (0) | 2022.06.19 |
전방 선언 (Forward Declaration) #22.11.22일 복습 (0) | 2022.06.10 |
LValue, RValue , 이동 생성자 깊게 이해하기 (feat.Copy Elision ) (0) | 2022.05.04 |