Back-end/C++

22.03.15 - 정적 멤버 변수, 정적 멤버 함수, 함수 호출 방식

giggs 2022. 3. 18. 16:44

 

강의 흐름 

  • 정적 멤버 변수와 정적 멤버 함수의 개념 설명
  • C++에서 함수의 호출 방식 3가지 체크

 


 

 

전날 복습

  • 객체가 만들어질 때 생성자 반드시 필요하다.
  • 내가 만들지 않으면 자동으로 컴파일러 만들어준다.
  •  
  • 생성자를 반드시 내가 만들어줘야 하는 경우 2가지
  • const형 변수가 있는 경우
  • 참조형(&) 변수가 있는 경우
  •  
  • 2가지 경우 - 생성자를 만들 시 생성자 초기화 리스트를 통해서만 초기화 가능
  •  
  • { } 중괄호 블록은 범위를 지정하는 데 사용 = scoupe라고 부른다.
  • 객체는 scoupe안에서만 통용되는 애다. - scoupe 빠져나갈 때 없어진다.

 

 


 

정적 멤버 변수

 

 

지정 형식 - static int count;

 

 


 

특징 1. 정적 멤버 변수는  클래스 밖에서 초기화해줘야 한다.

 

클래스 밖에서 초기화

 


 

특징 2. 정적 멤버 변수의 위치는 클래스 영역이다. ( = 클래스 변수 )

 

 

 

 

8~11번  line - 일반 멤버 변수와 정적 멤버 변수가 있고

17~21번  line - 객체가 생성될 때마다 count++ 해준다고 한 상태에서

 

 

객체 a1, a2, a3를 생성하는 상황을 가정해보면

a1, a2, a3 객체의 메모리에는 각각 일반 멤버 변수들( name, age, grade, classnum)이 자리 잡고 있을 것이고,

 

 

 

그 뒤에 정적 멤버 변수 count도 같이 자리 잡고 있는 것이다? 결론부터 말하면 NO!

 

 

정적 멤버변수인 count는 일반 멤버변수처럼 객체안에 있는 것이 아니다.

 

 

정적 멤버 변수 count가

만약 일반 멤버 변수와 같이 객체 안에 자리 잡고 있다면 객체가 생길 때마다 +1 해주는 것이므로

a1에서 count=1   ///   a2에서 count = 1  ///    a3에서 count =1 이 될 것이다. 

일반 멤버 변수와 다를 것이 없어진다. 

 

 

 

 

그렇다면 정적 멤버 변수 count는 어디에 있는 것인가?

 

클래스 영역에 하나만 만들어지는 static 변수 - 객체들이 이것을 공유해서 사용

 

 

static 변수 - 정적 변수는 객체에 섞여있지 않고, 클래스 영역이라는 곳에 하나만 만들어진다.

그 공간을 객체들이 공유해서 사용하는 것이다.

객체에 속해있지 않고 클래스에 속해있다고 하여서 정적 변수를 ( = 클래스 변수 )라고도 한다.

 

 


 

 

특징 3. 객체를 통해서 접근하지 않아도 클래스로 바로 접근 가능하다.

 

클래스로 접근 가능! Student :: Count 

 

 

일밤 멤버 변수는 객체를 생성하고 그 객체를 통해서만 접근할 수 있지만,

static 변수는 클래스에 속해있기 때문에, 객체를 통해서 접근하지 않아도 바로 접근할 수 있다.

 

 

60번 Line -> 57번 Line

a1.GetCount() --- 변경 가능 ---> Student :: Count로 가능!

 

 

 

실제 사용하는 경우

ex 게임에서 맵에 몬스터 개수 제한 줄 경우! 200마리 이하로 유지할 때

ex 객체들 통제할 때 count 만 바꿔주면 모든 객체에 영향

 

 

 


 

정적 멤버 함수

 

 

지정 형식 : static int add( ) { } 

 

 

 


 

특징 1. 정적 멤버 변수와 같이 객체에 속해있지 않고 클래스 영역에 속해 있다. ( = 클래스 함수 )라고 한다.

 


 

특징 2. 정적 멤버 함수 안에서는 일반 멤버 변수, 함수에 접근 불가능

 

 

 

 

접근이 불가능한 이유는?

  • 일반 멤버 함수는 객체가 만들어질 때 생기는 것인데, ( 객체 생겨야 호출 가능 )
  • 정적 멤버 변수나 함수는 객체가 만들어지지 않아도 생기는 것이다.( 객체 생기지 않아도 호출 가능 )

없는 거에 접근하는 것이 되므로 - 정적 멤버 함수 안에서 - 일반 멤버 함수, 변수사용 불가능 X

 

 


 

특징 3. 객체를 통해서 접근하지 않아도, 클래스를 통해서 접근 가능하다. +객체를 통해서도 호출 가능

 

 

 

28번 Line -- c.add(a, b)처럼 객체를 통해서 함수를 호출해서 사용해야 하는 - 일반 멤버 함수

29번 Line -- Utility::sub(a, b)처럼 객체 생성 없이도 클래스를 통해 함수를 호출해서 사용하는 - 정적 멤버 함수

 

 

14번 Line -- sub( )는 정적 멤버 함수

32번 Line -- 정적 멤버 함수는 객체를 통해서 호출하는 방식도 사용 가능 - c.sub(a, b) 도 가능

 

 


 

 

함수 호출 방식

 

 

먼저 함수 = function의 구성 요소

 

 

1. returntype 

  • 함수 연산을 끝내고 반환 값 어떤 타입인지 지정 필요
  • return 값없으면 void 
  • return 값있으면 함수 내부에 return 반드시 필요!

2. 함수명( 매개변수 ) 

  • 함수명 add
  • 매개변수 ( int a, int b)

3. 명령어

  • int sum = a + b;
  • return sum;

 


 

 

함수의 값을 전달하는 3가지 방법

 

함수의 매개변수에 - 인자 값을 - 전달하는 3가지 방법

 

 

  1. call by value ( 값에 의한 호출 )
  2. call by address ( 주소 값에 의한 호출 )
  3. call by reference ( 참조 값에 의한 호출 )

 

 

인자가 -> 매개변수로 전달

이때 전달될 수 있는 인자의 값 - 3가지에 따라 명칭이 다르다.

 


 

 

먼저 인자 ( argument )와 매개변수 ( parameter )의 구분

 

 

main 의 a,b는 인자 // add의 a,b 는 매개변수 // 메모리 저장되는 공간도 다름

 

 

main에 a, b랑 ( = 인자 ) 

add함수의  a, b랑 ( = 매개변수 ) 다름!

 

 

이름만 같은 애일뿐 강남 사는 a, b 제주도 사는 a, b각자의 스쿠프 {  } 안에서만 존재하고 끝나면 사라짐

 


 

1. call by value - 값에 의한 호출

 

 

 

main a,b 인자가 값으로 add함수의 매개변수로 전달

 

 

main에서 생성된 int a, b - 인자 값으로 a와 b 가 -

add 함수를 호출하면서 --- add 함수의 매개변수로 전달 되게 된다.

이때 전달되는 것이 20과  30이라는 값으로 전달된다.

 

 

이처럼 함수를 호출하면서 인자 값을 -> 함수의 매개변수로 전달하는 것을 call by value라고 한다.

 

 

 


 

 

2. call by address - 주소 값에 의한 호출

 

 

main a,b 인자가 주소 값으로 padd함수의 매개변수로 전달

 

 

main에서 생성된 int a, b - 여기에서는 인자로  a와 b의 값이 아닌  - 인자로 &a, &b 가- 변수 a와 b의 주소 값이

padd 함수를 호출하면서 --- padd 함수의 매개변수로 전달 되게 된다.

이때 전달되는 것이 20과  30이라는 값이 아닌 20이 저장되어있는 주소 값과 30이 저장되어있는 주소 값으로 전달된다.

 

 

이처럼 함수를 호출하면서 인자의 주소 값을 -> 함수의 매개변수로 전달하는 것을 call by address라고 한다.

 

 

 

+@

 

21번 Line - int형 주소 값을 저장하는 포인터형 변수 pa, pb 만들어지고 ( * 포인터 형 지정자로 사용 )

21번 Line - 거기에 a변수의 주소 값&a, b변수의 주소 값&b가 인자 값으로 전달된다. 

 

22번 Line - pa라는 변수에는 &a 가 저장되어있는데 *pa를 하면 *&a와 같다.( * 포인터 연산자로 사용 )

22번 Line - *&a => a의 주소 값을 저장하고 있는 공간을 의미 = 이것은 곧 a와 같다. ( *&a = a ) 

 

 

포인터 연산자의 역할 -> 해당 주소 위치에서부터 할당받은 공간을 의미!

 

 

temp = *pa + *pb;

temp = *(&a) + *(&b);

temp = *&a + *&b;

temp = a + b;

 

 

call by address의 체크 포인트!

  • 여기서 넘어온 a의 주소 값 --- &a는 main안에 있는 a의 주소 값이다. 
  • 기본적으로 main에 있는 변수 a와 b는 다른 곳에서 접근할 수 없다.
  • main의 스쿠프{  } 안에서만 사용하고 없어지는 애인데,
  • padd 함수 안에서 - 넘어온 주소 값을 가지고 - main의 변수 a와 b에 접근 가능하다 - 영향을 줄 수 있다.
  • 이런 상황을 결합도가 올라간다고 말하며, 좋은 것이 아니다.

 

 


 

3. call by reference 

 

 

내부적으로 돌아가는 방법은 call by address와 동일

 

 

main a,b 인자가 주소 값으로 refadd함수의 매개변수로 전달

 

 

main에서 생성된 int a, b - 여기에서는 인자로  a와 b의 값이 아닌  - 인자로 &a, &b 가 = 변수 a와 b의 주소 값이

refadd 함수를 호출하면서 --- refadd 함수의 매개변수로 전달 되게 된다.

이때 전달되는 것이 20과  30이라는 값이 아닌 20이 저장되어있는 주소 값과 30이 저장되어있는 주소 값으로 전달된다.

 

이처럼 함수를 호출하면서 인자의 주소 값을 -> 함수의 매개변수로 전달하는 것을 call by reference라고 한다.

 

 

call by reference의 체크 포인트!

  • refa , refb라는 메모리 공간이 새로 생기는 것이 아니다.
  • a, b를 가리키는 별칭이 하나 더 생긴 것이다. - 접근할 수 있는 방법만 하나 더 생긴 것이다.
  • 참조형도 매개 변수로 주소 값이 들어오는데, 한번 지정되면 변경 불가능하다. 
  • 한 번 연결되는 순간 바꿀 수 없다. - fix 시켜버린다.
  • 포인터형은 전달받은 주소 값 변경 가능

 


 

객체를 매개변수의 인자로 전달할 경우 :: 참조형으로 전달하는 것이 유리하다

 

 

A 클래스가 있고

 


 

2가지의 함수를 만들고 

 


출력 TEST 

 

a만 그렸지만, b도 동일

 

 

함수 addclassA는 객체의 값을 전달받는 것으로 그대로 입력된다.

int 3개 12byte ( a )와 int 3개 12byte ( b ) 그대로 대입 - 24byte가 공간 차지.

 

함수 addclassRefA는 객체의 주소 값 만들 전달받는 것이다.

객체의 크기가 12byte 이던지  1,200byte 이던지 상관없이 주소 값을 저장할 공간 4byte만 차지! 


 

이렇듯 참조형으로 전달하면 메모리면에서 유리 - 속도 향상에도 기여

 

메모리면에서 유리, 한 번 연결되면 변경 불가능한 특징 이용.

참조값을 주소 값이라고 하진 않는다. --- 내부적으로는 주소 값이 맞지만 --- 참조 값은 변수를 가리키는 값이라고 한다.

위험성도 존재 – 전달된 주소 값으로 main의 함수에 접근 가능하다는 것.

 

 


 

 

review



이번 강의에서 기억 남는 부분은 함수의 매개변수에 인자 값을 전달하는 3가지 방법!
 call by value // call by address // call by reference
객체의 값을  // 객체의 주소 값을  // 참조값 - 변수를 가리키는 값을 전달하는 방법!

참조형의 특징에 대해 더 알게 되었고,포인터 형과 참조형. 또 만나니 반가웠다 :)


이번 강의에서 정적멤버변수는
클래스 밖에서 초기화를 해줘야되는 부분과 초기화하는 형식도 알게 되었다.
클래스 내부에서 선언 -> static int Count; 
클래스 밖에서 초기화 -> Student :: Count = 0;

이 부분 말고는 정적 멤버 함수 내부에는 일반 멤버 변수와 함수는 사용 못한다는 점
클래스 영역에 존재해서 객체 생성 없이 클래스로 접근 가능하다는 점
java에서의 Static 변수, 함수 사용과 비슷해서 이해하기 수월했다.

클래스를 통해 함수 호출하는 법 - 추가적으로 체크 - Utility :: add(a, b); 이런 식으로 호출!


흐아.. 정리를 하며 복습이 되니까 다시 보는 면은 좋은데...
시간이 오래 걸려서 다른 공부할 시간이 줄어든다.
나중에 참고용으로만 볼 생각하고
알았던 부분은 생략하고 새로운 부분들만 추려서 올려야 하나 생각도 든다. 

현재 생각은 이 글을 보며 나중에 혹시라도 남을 가르쳐 줄 상황을 생각하며 글을 작성하고 있다.
가르쳐 주면서 나도 더 배우고, 개념을 더 단단하게 세울 수 있을 것이니까.
후후 고민을 더 해봐야겠다.