클래스의 static 멤버 변수는 객체가 소멸될 때 소멸되는 것이 아닌 프로그램이 종료될 때 소멸됨
클래스의 모든 객체들이 '공유'하는 변수로써 각 객체 별로 따로 존재하는 멤버 변수들과는 달리
모든 객체들이 '하나의' static 멤버 변수를 사용하게 됨
모든 전역 및 static 변수들은 정의와 동시에 값이 자동으로 0으로 초기화 되지만
클래스 static 변수들은 초기화 필요
사용 방법
클래스에 변수 정의 (ex) static int total_marine_num;
초기화 (ex) int Marine::total_marine_num = 0;
// static 멤버 변수의 사용
#include <iostream>
class Marine
{
static int total_marine_num;
int hp; // 마린 체력
int coord_x, coord_y; // 마린 위치
bool is_dead;
const int default_damage; // 기본 공격력
public:
Marine(); // 기본 생성자
Marine(int x, int y); // x, y 좌표에 마린 생성
Marine(int x, int y, int default_damage);
int attack(); // 데미지를 리턴한다.
void be_attacked(int damage_earn); // 입는 데미지
void move(int x, int y); // 새로운 위치
void show_status(); // 상태를 보여준다.
~Marine() { total_marine_num--; }
};
int Marine::total_marine_num = 0;
Marine::Marine()
: hp(50), coord_x(0), coord_y(0), default_damage(5), is_dead(false)
{
total_marine_num++;
}
Marine::Marine(int x, int y)
: coord_x(x), coord_y(y), hp(50), default_damage(5), is_dead(false)
{
total_marine_num++;
}
Marine::Marine(int x, int y, int default_damage)
: coord_x(x),
coord_y(y),
hp(50),
default_damage(default_damage),
is_dead(false)
{
total_marine_num++;
}
void Marine::move(int x, int y)
{
coord_x = x;
coord_y = y;
}
int Marine::attack() { return default_damage; }
void Marine::be_attacked(int damage_earn)
{
hp -= damage_earn;
if (hp <= 0) is_dead = true;
}
void Marine::show_status()
{
std::cout << " *** Marine *** " << std::endl;
std::cout << " Location : ( " << coord_x << " , " << coord_y << " ) "
<< std::endl;
std::cout << " HP : " << hp << std::endl;
std::cout << " 현재 총 마린 수 : " << total_marine_num << std::endl;
}
void create_marine()
{
Marine marine3(10, 10, 4);
marine3.show_status();
}
int main()
{
Marine marine1(2, 3, 5);
marine1.show_status();
Marine marine2(3, 5, 10);
marine2.show_status();
create_marine();
std::cout << std::endl << "마린 1 이 마린 2 를 공격! " << std::endl;
marine2.be_attacked(marine1.attack());
marine1.show_status();
marine2.show_status();
}
static 멤버 함수 역시 클래스 전체에 딱 1개만 존재하는 함수
객체 없이도 클래스 자체에서 호출 가능
객체.멤버 함수()가 아닌 클래스명::static 함수() 형식으로 호출함
호출 방법
클래스::static 함수 (예) Marine::show_total_marine();
#include <iostream>
class Marine
{
// 중복 코드 생략
public:
static void show_total_marine();
}
void Marine::show_total_marine()
{
std::cout << "전체 마린 수 : " << total_marine_num << std::endl;
}
int main()
{
Marine marine1(2, 3, 5);
Marine::show_total_marine();
Marine marine2(3, 5, 10);
Marine::show_total_marine();
create_marine();
std::cout << std::endl << "마린 1 이 마린 2 를 공격! " << std::endl;
marine2.be_attacked(marine1.attack());
marine1.show_status();
marine2.show_status();
}
(주의) static 함수 내에서 일반 멤버 변수를 사용하면 누구의 멤버 변수인지 모르는 상황 발생
자기 자신을 가리키는 포인터
클래스 안에서 정의된 함수 중 this 키워드가 없는 함수는 static 함수 뿐임
#include <iostream>
Marine& Marine::be_attacked(int damage_earn)
{
hp -= damage_earn;
if (hp <= 0) is_dead = true;
return *this;
}
// 레퍼런스를 리턴하는 함수
#include <iostream>
class A
{
int x;
public:
A(int c) : x(c) {}
int& access_x() { return x; }
int get_x() { return x; }
void show_x() { std::cout << x << std::endl; }
};
int main()
{
A a(5);
a.show_x();
int& c = a.access_x();
c = 4;
a.show_x();
int d = a.access_x();
d = 3;
a.show_x();
// 아래는 오류
// int& e = a.get_x(); // 임시로 복사생성
// e = 2;
// a.show_x();
int f = a.get_x();
f = 1;
a.show_x();
}
실행 결과
5
4
4
4
int& access_x() { return x; } // x의 레퍼런스 리턴
int get_x() { return x; } // x의 값 리턴
int& c = a.access_x(); // c는 x의 별명을 받음
c = 4; // c에 새로운 값을 대입하면 a의 x의 값을 바꾸는 의미
a.show_x(); // a의 값이 5 -> 4로 바뀜
int d = a.access_x(); // int 변수에 x의 별명(값)을 전달
d = 3; // d의 값을 바꿔도
a.show_x(); // a에는 영향을 주지 않음 -> 여전히 출력 결과는 4
주석 부분을 풀면 오류가 발생됨 (C2440)
레퍼런스가 아닌 타입을 리턴하는 경우는 '값'의 복사가 이루어지기 때문에 임시 객체가 생성되는데
임시객체(문장이 끝나면 소멸됨)의 레퍼런스를 가질 수 없기 때문임
// 레퍼런스를 리턴하는 함수는 그 함수 부분을 리턴하는 원래 변수로도 치환 가능
a.access_x() = 3;
// 즉, 위 문장을 아래와 같이 표현 가능
a.x = 3;
// 그러나 아래와 같이는 사용 불가
a.get_x() = 3;
// get_x()가 리턴하면서 생성되는 임시 객체로 치환되므로
// 임시 객체에 대입을 하게 되는 모순적인 상황임
상수 멤버 함수로 정의되면 다른 변수의 값을 바꾸지 않는 함수로 프로그래머에게 명시할 수 있음
상수 함수 내에서는 객체들의 '읽기'만 가능하며, 함수는 다른 상수 함수만 호출 가능
사용 방법
함수의 정의 const; (ex) int attack() const;
함수의 구현에도 const를 붙여야 함
#include <iostream>
class Marine
{
int attack() const;
}
int Marine::attack() const { return default_damage; }
int main()
{
Marine marine1(2, 3, 5);
marine1.show_status();
Marine marine2(3, 5, 10);
marine2.show_status();
std::cout << std::endl << "마린 1 이 마린 2 를 두 번 공격! " << std::endl;
marine2.be_attacked(marine1.attack()).be_attacked(marine1.attack());
marine1.show_status();
marine2.show_status();
}