[C++] static 멤버 변수, 멤버 함수, this, const 함수

·2023년 8월 19일
0

C++

목록 보기
7/17
post-custom-banner

static 멤버 변수

클래스의 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 멤버 함수

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

자기 자신을 가리키는 포인터
클래스 안에서 정의된 함수 중 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 함수

상수 멤버 함수로 정의되면 다른 변수의 값을 바꾸지 않는 함수로 프로그래머에게 명시할 수 있음
상수 함수 내에서는 객체들의 '읽기'만 가능하며, 함수는 다른 상수 함수만 호출 가능

사용 방법
함수의 정의 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();
}
post-custom-banner

0개의 댓글