Powerful Language C++
C++에서 static, const, explicit이라는 생소할 수도 있고 생소하지 않을 수도 있는 키워드가 존재합니다. 하지만, 뭐 무조건 이걸 써야 한다 이런 개념은 아니지만, 위와 같은 키워드를 통해서 객체지향 개념을 비로소 완성시킬 수 있습니다. 객체 지향 패러다임은 많은 부분을 지향하지만, 그중에서도 캡슐화, 객체 보호 등 많은 부분들을 챙겨서 지켜야 합니다. 실제 프로그래밍에서 손상되지 않아야 할 영역들은 위와 같은 키워드를 통해서 컴파일러에 전달해 최우선적으로 보호해야 하기 때문입니다. 그렇다면 순서대로 한번 해보도록 하겠습니다!!
Static in C++
Static 키워드는 변수 혹은 객체를 정적 변수화를 의미합니다. 물론 의미전달은 컴파일러를 통해 컴퓨터에게 전달되겠죠? 변수 혹은 객체가 static으로 선언되면, 해당 변수의 메모리 공간은 프로그램 루틴이 살아있는 동안은 정적으로, 그러니까 무조건적으로 확보되어 할당됩니다. 이는 루틴이 돌아간 이후에 어떤 누구도 변경할 수 없는 상태라는 의미입니다. 만약 함수 내부에 선언된 static변수 같은 경우는 처음 호출된 순간, 그 순간만 할당되고 이후에 호출하더라도 메모리 공간에는 변함이 없습니다. 다른 말로 하면 다른 함수 혹은 객체 내부에서 statement를 저장해야 할 때 저흰 코루틴 개념을 사용해서 호출하거나 사용하게 되는데 이때 유용하다는 의미입니다. 아래 예제 코드를 보도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
void CallStatic(){
static int num = 1;
num++;
cout << num << endl;
}
int
main()
{
for (int i = 0; i < 5; i++)
CallStatic();
return 0;
}
result >> 2,3,4,5,6
|
cs |
static변수는 마치 전역 변수와도 비슷하게 동작되어 사용되기도 합니다. 그렇기 때문에 몇번을 호출해도 아래 결괏값과 같이 출력되게 되는 거죠, 전역 static변수가 선언되더라도 이는 동일합니다. 하지만 그렇게 선언했을 시 아래와 같이 함수 또한 static키워드를 사용해서 정적 함수로서 동작하게 해야 합니다. 물론 일반적인 함수에서 그렇게 붙지 않더라도 static멤버 함수가 아니라면 컴파일도 되고 동작도 하지만, 코드상 규칙은 지켜주시기 바랍니다...^^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
static int num2 = 0;
static void CallStatic2(){
num2++;
cout << num2 << endl;
}
void StaticError(){
num2++;
cout << num2 << endl;
}
int
main()
{
for (int i = 0; i < 5; i++)
CallStatic2();
StaticError();
return 0;
}
result >> 1,2,3,4,5,6
|
cs |
위처럼 작성하시고 반드시 작성 후 컴파일 해야합니다!
Static in Class
클래스에서 정적 변수를 사용해보도록 하겠습니다. 사실 이 부분이 제일 중요하고 애매한 부분 또한 많이 존재합니다. static변수는 아까도 말씀드렸듯이 정적 공간에 할당되어 한번만 초기화되고 다시 메모리를 할당받거나 하지 않습니다. 그렇기 때문에 객체는 인스턴스화를 통해서 할당받지만, 그 이전에 메모리를 할당받습니다. 또한 동일한 객체가 존재하는 경우가 존재하겠죠? 그렇기 때문에 생성자(Constructor)에서는 정적 변수를 초기화할 수 없습니다. 아래 코드 예제를 보도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Foo{
public:
static int bar;
Foo(){};
~Foo(){cout << "bye" << endl;};
//Foo(){bar = 1;} <--- symbol not found error occur plz don't
};
int Foo::bar = 10;
int
main()
{
Foo foo;
// Foo::foo.bar =1; <--- instance Error
cout << foo.bar << endl;
return 0;
}
result >> 10, bye
|
cs |
해선 안 되는 부분들은 모두 주석 처리했습니다. 한번 읽어보시면 이해가 갈듯 합니다.
- 생성자에서 정적변수 초기화는 할 수 없다
- 그렇기 때문에 명시적으로 정적변수를 전역범위에서 값을 초기화하는 것만 가능하다
- 당연히 어떤 함수의 범위든 내부에서 초기화하는 것은 절대적으로 불가능하다
이 부분만 지켜주시면 객체 지향 개념을 보호하면서 동시에 강력한 C++ 프로그래밍이 가능합니다. 아래 예제만 마지막으로 보고 넘어가도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class Foo{
public:
static int bar;
Foo(){cout << "hello" << endl;};
~Foo(){cout << "bye" << endl;};
//Foo(){bar = 1;} <--- symbol not found error occur plz don't
};
int Foo::bar = 10;
int
main()
{
int foobar = 0;
if (foobar == 0){
Foo foo;
cout << foo.bar << endl;
}
cout << "ha ?" << endl;
return 0;
}
result >> hello,10, bye, ha ?
|
cs |
자 위 코드를 보고 이상한 걸 느끼신 분이 계시면 감이 좋으신 거죠? 네 바로 변수와 마찬가지로 정적 객체로 선언된 객체는 프로그램 수명까지 범위를 갖는다고 말씀드렸습니다. 하지만 위 코드를 보면 ha?라고 출력하기 이전에 객체가 소멸된 부분을 확인할 수 있습니다. 그러니까 임의의 범위 내부에서 선언된 정적 객체는 정적 객체로 할당되는 것이 아닌 비정 적객체로 선언됩니다. 그렇기 때문에 당연히 제어문 내부에서만 할당돼있는 것입니다. 하지만 이를 만약 정적 객체로 선언하게 되면 어떻게 될까요?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class Foo{
public:
static int bar;
Foo(){cout << "hello" << endl;};
~Foo(){cout << "bye" << endl;};
//Foo(){bar = 1;} <--- symbol not found error occur plz don't
};
int Foo::bar = 10;
int
main()
{
int foobar = 0;
if (foobar == 0){
static Foo foo;
cout << foo.bar << endl;
}
cout << "ha ?" << endl;
return 0;
}
result >> hello,10, ha?, bye
|
cs |
보시면 바로 아시겠죠? 정적으로 선언되게 되면 당연히 정적으로 선언되기 때문에 if제어문과 관계없이 수명이 유지된 점을 확인할 수 있습니다. 그렇다면 클래스 내부의 정적 함수는 어떻게 구현되는지만 보고 진짜 마무리 짓도록 하겠습니다!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
class Foo{
public:
static int bar;
Foo(){cout << "hello" << endl;};
~Foo(){cout << "bye" << endl;};
static void Show(){
cout << "foo bar value is : " << bar << endl;
};// static member function implemented in class area
//Foo(){bar = 1;} <--- symbol not found error occur plz don't
};
int Foo::bar = 10;
//static void Foo::Show... <--- It can't be done : (
int
main()
{
int foobar = 0;
Foo::Show(); // Possible to Compile because already allocate
if (foobar == 0){
static Foo foo;
foo.Show(); // It can Compile too
cout << foo.bar << endl;
}
cout << "ha ?" << endl;
return 0;
}
result >>
foo bar value is : 10
hello
foo bar value is : 10
10
ha ?
bye
|
cs |
코드상에도 설명을 부연했지만 다시 한번 설명드리면 아래와 같습니다.
- 정적 멤버함수는 클래스 내부에서 선언 및 작성되어야 함
- 다른 영역의 함수에서 명시적 호출이 가능함, 이미 function table에 할당되었기 때문
이 정도만 알아도 static에 관한 사용은 자유롭게 할 수 있다고 생각합니다. 사실 const, explicit 또한 같이 설명하려 했으나 static만 해도 어마어마하기 때문에 이 정도로 정리한 것도 압축했다고 생각합니다!! 다음번에 const와 explicit에 관해서 올리겠습니다!!
댓글로 피드백, 문의, 질문 모두 환영합니다!!
감사합니다!!^^
'C++' 카테고리의 다른 글
[C++] extern, volatile 제대로 알고 사용하기! (0) | 2020.12.21 |
---|---|
[C++] static, const, explicit 제대로 알고 사용하기![2] (0) | 2020.12.19 |
C++로 구현하는 자료구조!!이중연결리스트(Doubly Linked List)@@ (1) | 2020.11.30 |
C++로 구현하는 자료구조!!!트리자료구조(Tree)@@ (1) | 2020.11.29 |
C++로 구현하는 자료구조!!!연결리스트(LinkedList)@@ (2) | 2020.11.28 |
댓글