[C++] 클래스 내부 static 멤버 변수,함수/ LNK2001, LNK1120 링크 오류

jh Seo·2022년 10월 21일
0

C++공부

목록 보기
9/21
post-custom-banner

개요

[C++] "비정적 멤버 참조는 특정 개체에 상대적이어야 합니다" 오류 글을 작성하면서
의문이 들었던 점인데,

class Snake{
private:
	char dir;
	int size;
	Node* head;
    Node* tail;
public:
    char Dir(char input = dir) {
		dir = input;
		return dir;
	}
};

일단 이 코드에서 잘못된부분은 멤버변수인 dir값을 디폴트매개변수로 사용하려 할 때,
컴파일 시점에서는 dir값을 모르므로 오류가 뜨는 것이였다.

"비정적 멤버 참조는 특정 개체에 상대적이어야 합니다" 오류가 떠서 dir값을 컴파일 시점에 알 수 있게 하기 위해 static키워드를 dir변수에 추가했으나 링크 오류LNK2001, LNK1120가 떠서

오류 해결도 하며 공부할겸
이번 기회에 애매했던 static 개념에 대해 더 자세히 알아보자고 생각했다.

따라서 클래스 내부에서 static을 사용하는 법을 공부하는김에 static에 대해 정리해보았다.

static

기본적인 특징으로는
1. static으로 전역변수를 선언한다면 다른 파일에서 참조가 불가능하고
해당 파일에서만 사용가능하다.
2. 함수 내에 선언된 static변수는 한 번 초기화되고, 함수 빠져나가도 지역변수와 다르게
소멸하지 않는다.

클래스에서 static 멤버변수 사용법

class Snake{
private:
	static char dir;
public:
    char Dir(char input = dir) {
		dir = input;
		return dir;
	}
};

위의 Snake클래스의 dir변수를 static으로 선언을 한다면,
Snake객체가 아무리 생겨도 dir변수는 단하나를 가리킨다

하지만 이렇게 작성한다면 개요에 적힌 코드처럼 구현단계와 컴파일단계에서
"비정적 멤버 참조는 특정 개체에 상대적이어야 합니다" 오류는 뜨지 않지만,
Snake 객체를 하나 만든 후, Dir함수를 호출하면 링크에러LNK2001, LNK1120가 뜬다.

찾아보니 static 멤버변수 dir변수를 초기화를 안 한다면 메모리에 할당이 안 된다고 한다!!
따라서 dir값을 호출할 때 오류가 나는 것이였다.

따라서 static멤버변수를 사용하려면 초기화를 해줄 필요가 있는데 방법이 두 가지 있다.

클래스내에서 static 변수를 초기화 하는 방법

  1. const 키워드를 사용하여

    const static char dir='a'; 

    이런 식으로 사용한다면 선언과 동시에 초기화할 수 있다는 장점이 있지만,
    const 키워드 때문에 내가 구현하려 했던 dir값을 변경하는 부분이 불가능해진다.

  2. 클래수 외부에서 초기화

    class Snake{
    private:
    	static char dir;
    public:
       char Dir(char input = dir) {
    		dir = input;
    		return dir;
    	}
    };
    char Snake::dir='a';

    이런식으로 클래스 외부에 작성하면 된다.
    사실 처음에 클래스 외부에 작성하라고 공부해서 외부? 하고
    main함수 안에다 작성했더니 적절한 범위가 아니라고 오류가 떠서 뭔가 했다.

    다른 함수 안에 적는게 아니라 전역변수형식으로 클래스 외부에서 초기화 하는 방식이였다.

-> 따라서 위의 첫번째 방법을 이용해 외부에 dir값을 초기화를 해줬더니
오류나 링크에러 뜨지않고 잘 작동되는 것을 확인 할 수 있었다.

초기화 말고 다른 특징

이 두 가지 방법을 활용하여 초기화를 하고 사용할 수 있는 데
static멤버변수의 접근성을 private이 아니라 public 으로 선언한다면

class Snake{
	
public:
	static char dir;
   
   char Dir(char input = dir) {
		dir = input;
		return dir;
	}
};
char Snake::dir='a';

이런 식으로 작성을 했을때

int main() {
	cout<<Snake::dir;
}

이런 main함수를 실행 시키면 Snake객체를 생성하지 않았으나 dir값을 잘 불러온다.
따라서 static변수는 클래스와 별개라는 것을 알 수 있다.

클래스 내에서 static 멤버함수 사용범

정리한김에 static멤버 함수도 조사한 결과,

static 멤버함수도 위에 적은 static 멤버변수와 동일하다.
1. 모든 클래스의 객체가 해당 멤버함수 공유
2. 클래스와 별개다
3. public 선언시 객체 선언 안 하고도 사용 가능

static멤버함수의 특징은 객체가 생성되기 전에 이미 존재하므로,
객체의 일반 멤버함수나 멤버변수를 사용할 수 없다.

따라서 static으로 선언된 멤버 변수나 멤버 함수만을 사용할 수 있다.

생각

이 부분을 공부하기 전에 예전에 배웠지만 희석된 개념은 const키워드는 상수로 만들어준다고 생각해서
static키워드나 const키워드나 다 미리 메모리에 할당된다라고 잘못 알고 있었고,
따라서

class Snake{
private:
	static char dir;
public:
    char Dir(char input = dir) {
		dir = input;
		return dir;
	}
};
char Snake::dir='a';

여기서 static 멤버변수 dir을 const char dir;로 변경해도 되겠다 싶었는데 안 되어서
굉장히 당황했었다.

알고보니 static은 프로세스의 시작과 동시에 메모리에 할당되지만(data 영역)
const키워드는 상수로 만들어주는게 아니라 단순히 변경할 수 없게 만드는 키워드라
컴파일 시점에 dir이 static 변수가 아닌 이상 모른다.

착각한 이유 중 하나는 const키워드를 전역변수 앞에 붙이던 게 기억나서,
const때문이 아니라 전역변수라서 메모리에 올라가는 데, const에 의미부여를 한 것 같다.

그래도 한번 정리하니 확실히 알게 된 것 같다.

profile
코딩 창고!
post-custom-banner

0개의 댓글