들어가며
클래스에 대해서 배우기 전에,
구조체에 대해서 알고 있음을 전제로
글을 진행해 나가기 때문에 구조체에 대한 이해가 부족하다면
이 블로그의 구조체에 관한 글을 먼저 읽고 오길 바란다.
C++에서의 구조체
본격적인 C++의 클래스를 배우기 전에 간단하게 알고 가자.
C에서 '구조체 변수'를 선언하는 방법은 다음과 같다.
struct weapon sword;
struct potion potion_red;
C++에서는 기본 자료형 변수의 선언 방식이나
구조체를 기반으로 정의된 자료형의 변수 선언 방식에 차이가 없다.
즉, C++에서는 별도의 typedef 선언 없이도 다음과 같이 변수를 선언할 수 있다.
weapon sword;
potion potion_red;
아무튼 이와 관련하여 구조체를 기반으로 코드를 구성해 보겠다.
#include <iostream>
using namespace std;
#define ID_len 30
#define MAX_DURABILITY 250
#define DURABILITY_DEBUFF 50
#define DURABILITY_STEP 2
struct WEAPON
{
char weaponID[ ID_len ]; // 무기 아이디
int dura; // 내구도
int dura_dbf; // 내구도 디버프 조건
int atk_dmg; // 공격력
};
void ShowWeaponState(const WEAPON& weapon)
{
cout << "Name: " << weapon.weaponID << endl;
cout << "Durability: " << "250/" << weapon.dura << endl;
cout << "Attack Damage: " << weapon.atk_dmg << endl << endl;
}
void Attack(WEAPON& weapon)
{
// 내구도가 0이면 공격력 0
if (weapon.dura <= 0)
{
cout << "The " << weapon.weaponID << " is broken." << endl << endl;
weapon.atk_dmg = 0;
return;
}
// 일정 수준 이하의 내구도는 공격력 감소 디버프
else if(weapon.dura_dbf == false && weapon.dura <= DURABILITY_DEBUFF)
{
weapon.atk_dmg = (weapon.atk_dmg / 2);
weapon.dura_dbf = true;
}
weapon.dura -= DURABILITY_STEP;
}
void Repair(WEAPON& weapon)
{
if (weapon.dura == MAX_DURABILITY)
return;
else if (weapon.dura < MAX_DURABILITY)
{
// 수리하면 내구도와 공격력 복구(디버프 해제)
if (weapon.dura_dbf == true)
{
weapon.atk_dmg = weapon.atk_dmg * 2;
weapon.dura_dbf = false;
}
weapon.dura = MAX_DURABILITY;
}
}
int main()
{
WEAPON sword = { "sword", MAX_DURABILITY, false, 8 };
Attack(sword);
ShowWeaponState(sword);
for (int i = 0; i < 100; i++)
{
Attack(sword);
if (sword.dura <= 0)
{ Attack(sword); break; }
}
ShowWeaponState(sword);
Repair(sword);
ShowWeaponState(sword);
for (int i = 0; i < 200; i++)
{
Attack(sword);
if (sword.dura <= 0)
{ Attack(sword); break; }
}
ShowWeaponState(sword);
return 0;
}
코드 꼬라지가 맘에 들지 않더라도 양해해 주길 바란다.
아직 규약이나 암묵적인 룰, 통용되는 코드 구성 및 명명법 등은
나도 알고 싶다.
그러니까 도움이 필요한 불쌍한 학생이다.
코드에 대해 설명하자면
장비 아이템의 '내구도'와 '공격력'에 대한 관계에 대해 작성했다.
내구도가 50이하일 때 공격력이 절반으로 감소,
내구도가 0이하일 때 공격력이 0으로 감소 및 메시지 출력.
뭐, 이런 식으로 말이다.
함수는 결국 데이터의 처리를 담당하는 도구이니,
데이터와 함께 부류를 형성하는 것은 매우 당연한 것이다.
따라서 필자는 위 코드에 정의된 세 개의 함수에 대해
다음과 같이 말할 것이다.
구조체 WEAPON과 함께 부류를 형성하여,
WEAPON과 관련된 데이터의 처리를 담당하는 함수들이다.
따라서 위의 함수들은 구조체 WEAPON에 종속적인
함수들이라고 말할 수 있다.
하지만 전역 함수의 형태를 띠기 때문에,
이 함수들이 구조체 WEAPON에 종속적임을
나타내지 못하고 있는 상황이다.
따라서 낄끼빠빠를 못 하고 다른 영역에서
이 함수를 호출해서 '형이 왜 거기서 나와?' 상황이
발생해도 이상하지 않은 상황이다.
야 구조체, 넣을게
구조체 WEAPON에 종속적인 함수들을 구조체 내부에
넣어버리면 어떨까라는 생각을 해볼 수 있지 않은가?
그렇게 되면 무기 아이템과 관련된 데이터와 함수들을
모두 묶는 셈이 되기 때문에 보다 확실한 구분이 가능하다.
앞선 코드를 재활용해서 한번 넣어보도록 하겠다.
C++에서는 구조체안에 함수를 삽입하는 것이 가능하니까 말이다.
struct WEAPON
{
char weaponID[ID_len]; // 무기 아이디
int dura; // 내구도
int dura_dbf; // 내구도 디버프 조건
int atk_dmg; // 공격력
void ShowWeaponState()
{
cout << "Name: " << weaponID << endl;
cout << "Durability: " << "250/" << dura << endl;
cout << "Attack Damage: " << atk_dmg << endl << endl;
}
void Attack()
{
// 내구도가 0이면 공격력 0
if (dura <= 0)
{
cout << "The " << weaponID << " is broken." << endl << endl;
atk_dmg = 0;
return;
}
// 일정 수준 이하의 내구도는 공격력 감소 디버프
else if (dura_dbf == false && dura <= DURABILITY_DEBUFF)
{
atk_dmg = (atk_dmg / 2);
dura_dbf = true;
}
dura -= DURABILITY_STEP;
}
void Repair()
{
if (dura == MAX_DURABILITY)
return;
else if (dura < MAX_DURABILITY)
{
// 수리하면 내구도와 공격력 복구(디버프 해제)
if (dura_dbf == true)
{
atk_dmg = atk_dmg * 2;
dura_dbf = false;
}
dura = MAX_DURABILITY;
}
}
};
구조체 내부에 삽입된 함수의 정의에 대해서
뭔가 변화가 일어났다는 것을 눈치챘는가?
그럼 ShowWeaponState 함수를 예로 확인해 보도록 하겠다.
먼저 다음의 코드는 삽입 이전의 코드다.
void ShowWeaponState(const WEAPON& weapon)
{
cout << "Name: " << weapon.weaponID << endl;
cout << "Durability: " << "250/" << weapon.dura << endl;
cout << "Attack Damage: " << weapon.atk_dmg << endl << endl;
}
이 함수는 매개변수를 통해서 연산 대상의 정보를 전달받는다.
그리고 함수 내에서도 참조자 weapon을 대상으로 연산(출력)을 진행한다.
반면에, 삽입 이후의 코드는
이들, 연산 대상의 정보가 존재하지 않는다.
void ShowWeaponState()
{
cout << "Name: " << weaponID << endl;
cout << "Durability: " << "250/" << dura << endl;
cout << "Attack Damage: " << atk_dmg << endl << endl;
}
가시적으로 확인할 수 있듯이,
매개 변수, 멤버 연산자를 통한 구조체 변수의 멤버 접근 등
연산 대상의 정보가 불필요해진 이유는,
함수가 구조체 내에 삽입되면서 구조체 내에 선언된 변수에
직접 접근이 가능해졌기 때문이다.
따라서 다음과 같이 구조체 변수를 각각 선언하면,
WEAPON sword_L = { "sword", MAX_DURABILITY, false, 8 };
WEAPON sword_R = { "dagger", MAX_DURABILITY, false, 8 };
다음의 형태로 구조체 변수가 생성된다.
'그럼 구조체 변수마다 함수가 별도로 정의되는 거임? 겁나 비효율적이누;;'
좋은 태클이다.
실제로는 다음의 그림처럼 하나의 함수를 공유한다.
그러나, 논리적으로는 각각의 변수가
자신의 함수를 별도로 지니는 것과 같은 효과 및 결과를 보이기 때문에
C++의 구조체 변수는 [그림 2]의 형태로 이해하는 것이 좋다.
아무튼, 완성된 코드를 확인해 보도록 하자.
#include <iostream>
using namespace std;
#define ID_len 30
#define MAX_DURABILITY 250
#define DURABILITY_DEBUFF 50
#define DURABILITY_STEP 2
struct WEAPON
{
char weaponID[ID_len]; // 무기 아이디
int dura; // 내구도
int dura_dbf; // 내구도 디버프 조건
int atk_dmg; // 공격력
void ShowWeaponState()
{
cout << "Name: " << weaponID << endl;
cout << "Durability: " << "250/" << dura << endl;
cout << "Attack Damage: " << atk_dmg << endl << endl;
}
void Attack()
{
// 내구도가 0이면 공격력 0
if (dura <= 0)
{
cout << "The " << weaponID << " is broken." << endl << endl;
atk_dmg = 0;
return;
}
// 일정 수준 이하의 내구도는 공격력 감소 디버프
else if (dura_dbf == false && dura <= DURABILITY_DEBUFF)
{
atk_dmg = (atk_dmg / 2);
dura_dbf = true;
}
dura -= DURABILITY_STEP;
}
void Repair()
{
if (dura == MAX_DURABILITY)
return;
else if (dura < MAX_DURABILITY)
{
// 수리하면 내구도와 공격력 복구(디버프 해제)
if (dura_dbf == true)
{
atk_dmg = atk_dmg * 2;
dura_dbf = false;
}
dura = MAX_DURABILITY;
}
}
};
int main()
{
WEAPON sword = { "sword", MAX_DURABILITY, false, 8 };
sword.Attack();
sword.ShowWeaponState();
for (int i = 0; i < 100; i++)
{
sword.Attack();
if (sword.dura <= 0)
{
sword.Attack(); break;
}
}
sword.ShowWeaponState();
sword.Repair();
sword.ShowWeaponState();
for (int i = 0; i < 200; i++)
{
sword.Attack();
if (sword.dura <= 0)
{
sword.Attack(); break;
}
}
sword.ShowWeaponState();
return 0;
}
위 코드의 main에서 보이듯이
세 함수는 더이상 전역 함수의 형태를 띄지 않고
함수들이 구조체 내부로 삽입되어
WEAPON 구조체에 대해서 종속적인 성격을 가지므로
구조체 변수의 멤버의 형태로 존재하고 있다.
따라서 함수를 호출할 때도 멤버 연산자를 통해서 접근해야 한다.
마치며
오늘은 클래스에 대해서 알아보고 싶었다.
하면 되지 왜 안 하는지 묻고 싶은가?
나도 알고 싶다.
본인은 '윤성우의 열혈 C++'을 기반 및 참고하여
여러 글을 작성하고 있기 때문에
아니 그전에 내가 공부하는 블로그지 않는가?
토달지 말길 바란다.
흥.
참고 및 출처
|