// cout 사용
#include <iostream>
// 문자열 관련 라이브러리
#include <string>
// 표준 라이브러리
using namespace std;
// 변수의 종류
// 1. 정적 변수(static variable)
// 2. 전역 변수(global variable)
// 3. 정적 멤버 변수 (static member varible)
// 4. 멤버 변수 (member variable)
// 5. 로컬 변수 (local variable)
// 6. 매개 변수 (Parameter, 인수(Argument))
// 1. 정적 변수(static variable)
// static 키워드는 블록{} 내에서 선언된 지역변수에서도 사용할 수 있다.
// 지역변수는 '자동주기(auto duration)'를 가지면 정의되는 시점에서 생성되고
// 초기화되며 정의된 블록이 끝나는 시점에서 소멸한다.
// static키워드를 사용한 지역변수는 자동주기에서 정적주기(static duration)으로 바뀐다.
// 이것을 정적변수라고 하는데 생성된 스코프(범위)룰 벗어나도 해당 값을 유지하는 변수다
// 정적변수는 한번만 초기화되며 프로그램 수명 내내 지속된다.
// (), {}, [], <>
// 테스트를 위해 Increasevalue라는 이름의 정적변수가 없는 함수를 정의해준다.
void Increasevalue()
{
// 기본적으로 자동 생명 주기이다.
// 함수를 빠져나가면 로컬변수 value는 소멸한다.
int value = 0;
// value변수의 값을 1증가시킨다.
value++;
cout << "value " << value << endl;
}// value는 여기서 소멸됨.
// IncreaseValueWithStatic 이라는 정적변수가 있느 함수를 정의해준다.
void IncreaseValueWithStatic()
{
// static 키워드가 들어간 정적 생명 주기 (static duration)입니다. 이 줄은 한번만 실행된다.
// 함수를 빠져 나가도 정적 멤버 변수인 s_intValue1은 소멸하지 않는다.
static int s_intValue1 = 0;
s_intValue1++;
cout << "s_intValue1 : " << s_intValue1 << endl;
}// s_intValue1은 소멸되지 않지만. 함수 안에 있기 때문에 접근할 수 없다.
// g_IntValue1이라는 이름의 전역변수를 선언해 준다.
// main() 함수 밖이 전역 공간이다. 함수 외부에서 정의된 변수는 전역 변수(Global Variable)이다
int g_IntValue1;
// 전역변수와 로컬변수의 이름이 같으면
// intValue2이라는 이름의 전역 변수를 선언해준다.
int intValue2 = 10;
// 테스트 StaticMemberVariable이라는 이름의 클래스를 정의한다.
class StaticMemberVariable
{
public:
// 정적 멤버 변수를 선언하고 있다.
// static 멤버 변수는 클래스 내에서 초기화를 하면 객체를 생성할 때마다 static멤버 변수 값이 계속해서
// 덮어질 것이다. 왜냐하면 모든 객체들이 이 멤버를 공유하기 때문이다
// static멤버 변수는 클래스 내에서 선언만 가능하고 정의는 불가능하다.
// static멤버 변수는 모든 객체들이 접근해야 하므로 프로그램 시작부터 끝까지 유지되어야 하기 때문에
// 전역 범위에서만 정의(초기화)할 수 있다,
// 따라서 static멤버 변수는 main함수는 물론이고 생성자 안에서도 초기화를 할 수 있다.
// 생성자도 static이어야 static 멤버 변수를 초기화할 수 있는데, C++에서는 static 생성자를 지원하지 않는다.
static int m_value;
//static int m_value1 = 1; // x
};
// 전역 범위에서 초기화를 해야한다.
// static멤버변수는 모든 객체가 공유해야 하므로 프로그램 전체 영역에서 메모리 유지가 되어야 한다.
// 따라서 반드시 전역 범위에서 정의 및 초기화를 해야한다.
int StaticMemberVariable::m_value = 1;
// StaticMemberFunction이라는 클래스를 정의해 준다.
class StaticMemberFunction
{
private:
// 일반 멤버 변수
int nomal_value = 99;
// 정적 멤버 변수
static int static_value;
public:
static void StatucFunction()
{
// 정적 멤버 함수 내의 일반 지역변수
int intValue1 = 1024;
cout << "intValue1 : " << intValue1 << endl;
cout << endl;
// 일반 멤버 변수는 사용할 수 없다.
//cout << "nomal_value : " << nomal_value << endl; // x
// 정적 멤버 변수는 사용 가능
cout << "static_value : " << static_value << endl;
cout << endl;
}
};
// 정적 멤버 변수는 전역 공간에서 초기화 해 주어야 한다.
int StaticMemberFunction::static_value = 2048;
// StaticClass1이라는 클래스를 정의해 준다.
class StaticClass1
{
private:
// private한 static멤버 변수
static int static_value;
public:
// static멤버함수
// 다른 클래스에서 private인 static 멤버 변수에 접근이 안되니 함수를 통해 접근한다.
static int GetValue()
{
return static_value;
}
};
// static멤버 변수는 전역공간에서 초기화를 해 준다.
int StaticClass1::static_value = 512;
int main()
{
// 함수가 호출되면 계속 초기화 되어서 결과값이 동일하다.
// Increasevalue() 함수를 호출할 때마다 value변수가 생성되고 0으로 초기화 된다.
// 그다음 변수의 값이 1 증가된다.
// Increasevalue() 함수의 실행이 완료되면 value변수는 범위를 벗어나 소멸된다.
Increasevalue();
Increasevalue();
Increasevalue();
Increasevalue();
Increasevalue();
cout << endl;
// IncreaseValueWithStatic 이라는 정적변수가 있느 함수를 정의해준다.
// 문장 추가하기
// staticValue는 static으로 선업되었기 때문에 StaticValue는 한 번만 생성되고 0으로 초기화 된다.
// 스코프(범위)를 벗어나도 소멸하지 않는다.
// IncreaseValueWithStatic() 함수가 호출될 때마다 StaticValue는 이전에 남겨둔 값이다,
// 하지만 함수 안에서 선언되었기 때문에 접근이 불가능하다.
IncreaseValueWithStatic();
IncreaseValueWithStatic();
IncreaseValueWithStatic();
IncreaseValueWithStatic();
IncreaseValueWithStatic();
cout << endl;
// g_IntValue1이라는 이름의 전역변수를 선언해 준다.
// 문장 추가
g_IntValue1 = 5;
cout << "g_IntValue1 : " << g_IntValue1 << endl;
cout << endl;
// 전역변수와 로컬변수의 이름이 같으면 ...
// intValue2이라는 이름의 전역 변수를 선언해준다.
// 문장 추가
// 전역 변수를 숨긴다.
// 전역 변수와 같은 이름을 가진 지역변수는 전역변수를 숨긴다.
// 그러나 범위 연산자(::)를 사용하면 컴파일러는 지역변수 대신 전역변수를 사용한다.
// 그러나 전역변수와 같은 이름의 지역변수를 선언하는 것은 피해야 한다.
// 관습에 따라 일반적으로 전역 변수를 정의할 때는 g_를 붙여 준다.
// 이 방법은 전역변수를 식별하는데 편리하고 지역변수와 충돌을 방지한다.
int intValue2 = 5;
intValue2++; // 지역 변수의 값을 증가시킨다.
::intValue2--; // 전역 변수의 값을 감소시킨다.
cout << "global intValue2 : " << ::intValue2 << endl;
cout << "local intValue2 : " << intValue2 << endl;
cout << endl;
// 정적 멤버 변수 (static member variable): 모든 객체가 한 메모리를 공유하는 멤버 변수이다.
// 객체별로 각각 할당되는 멤버가 아니라 모든 객체가 공유하는 멤버 변수이다.
// 메모리는 프로그램 시작때부터 차지하고 있으면 메모리에 항상 값이 유지된다.
// 객체 생성 전에 메모리에 존재한다. 따라서 객체 생성전에 초기화를 해 주어야 한다.
// 객체와는 독립적으로 존재한다.
// 객체 이름으로도 접근이 가능하지만 클래스 이름으로도 접근 가능하다.
// 테스트 StaticMemberVariable이라는 이름의 클래스를 정의한다.
// 문장 추가
// 전역 범위에서만 가능. 지역범위에서 선언하려고 하면 에러
//int StaticMemberVariable::m_value = 1; // x
// 객체 생성 전에도 사용이 가능하다.
// &StaticMemberVariable::m_value 의 &(주소 연산자)입니다.
cout << "value : " << StaticMemberVariable::m_value << ", address : " << &StaticMemberVariable::m_value << endl;
cout << endl;
// 객체 생성
StaticMemberVariable st1;
StaticMemberVariable st2;
st1.m_value = 512;
cout << "st1 value : " << st1.m_value << ", st1 address : " << &st1.m_value << endl;
cout << "st2 value : " << st2.m_value << ", st2 address : " << &st2.m_value << endl;
cout << endl;
st2.m_value = 1024;
// &st1.m_value, &st2.m_value, &StaticMemberVariable::m_value 전부 주소가 동일하다.
// 따라서 st1.m_value 값을 바꾸면 st2.m_value StaticMemberVariable::m_value 값들도 동시에 바뀐다.
// 모든 객체는 static 변수의 메모리를 공유하기 때문이다.
cout << "st1 value : " << st1.m_value << ", st1 address : " << &st1.m_value << endl;
cout << "st2 value : " << st2.m_value << ", st2 address : " << &st2.m_value << endl;
cout << "m_value : " << StaticMemberVariable::m_value << ", m_value address : " << &StaticMemberVariable::m_value << endl;
cout << endl;
// 4. 정적 멤버 함수
// static 멤버 함수란
// static 멤버 변수처럼 객체 이름은 물론이고, 클래스 이름으로도 접근 가능하다.
// 객체와 독립적이다. 따라서 객체 생성과 상관이 없다.
// 일반적으로 멤버 변수느 객체가 생성되어야 메모리를 할당받기 때문에
// static 멤버 함수 안에서는 멤버 변수를 사용할 수 없다.
// 그러나 미리 전역에서 메모리가 할당되는 static멤버변수는 사용이 가능하다.
// StaticMemberFunction이라는 클래스를 정의해 준다.
// 문장 추가
// 객체 생성 없이 바로 클래스 이름으로 호출이 가능하다.
StaticMemberFunction::StatucFunction();
// static 멤버 함수를 사용하는 이유
// 객체 생성 여부와 상관없이 클래스 이름으로 접근하고 싶을 때 사용하지만
// 주로 private인 static멤버 변수에 접근하려 할 때 많이 쓰인다.
// Static 멤버 변수는 모든 객체들이 사용하고 공유해야 하는데
// private 이면 외부에서 직접 접근하고 사용할 수 없다.
// private 인 멤버 변수들은 멤버 함수들에서만 접근이 가능하다는 특징이 있다.
// Static 멤버 함수를 톨해서 private한 static 멤버 변수에 간접적으로 접근할 수 있도록 구현할 수 있다.
// StaticClass1이라는 클래스를 정의해 준다.
// 문장 추가
//private이므로 직접 접근 불가능 하다.
//cout << StaticClass1::static_value << endl; // x
// 이처럼 private한 static 멤버 변수를 직접 접근할 수는 업지만
// static한 멤버 함수 GetValue()를 통해 접근 가능하다.
// 1. 클래스 이름으로 GetValue()함수를 호출할 수 있다.
cout << "StaticClass1.GetValue() : " << StaticClass1::GetValue() << endl;
cout << endl;
// 2. 객체 이름으로 GetValue() 함수를 호출할 수 있다
StaticClass1 staticClass1;
cout << "staticClass1.GetValue() : " << staticClass1.GetValue() << endl;
cout << endl;
}