.
을 누르면 객체를 사용할 수 있다.💡 객체지향프로그래밍의 4대 특징
1. 추상화 ⇒ 현실에 존재하는 대상의 특성과 기능을 파악하여 정의한다.
2. 상속
3. 다형성
4. 캡슐화 ⇒ 객체가 모든 것을 외부에 공개할 필요는 없다.
// 외부(전역)
class Monster
{
// 멤버
public:
int publicint;
void publicfunction()
{
protectedint = 20;
protectedfunction();
privateint = 20;
privatefunction();
}
protected:
int protectedint;
void protectedfunction()
{
}
private:
int privateint;
void privatefunction()
{
}
};
class Player
{
// 외부
public:
int GetHp()
{
return Hp;
}
void SetHp(int _Value)
{
if (_Value == 0)
{
}
Hp = _Value;
}
// 멤버면수는 private에 두고, get 함수와 set 함수를 만들어 사용한다
// 절대 변수를 외부에서 그냥 접근하지 못하도록 하는 것이 안전하고 좋다
protected:
private:
int Hp;
int Att;
// 변수는 기본적으로 private 또는 protected
};
int TestValue = 200;
int GetTest()
{
return TestValue;
}
class BossMonster
{
// 디폴트 접근제한지정자는 private이다
int Hp;
int Att;
};
int main()
{
// 외부(지역)
int Value = GetTest(); // 200
Value = 3000; // 3000
Monster NewMonster = Monster();
// NewMonster. => 라고 쳤을 때 publicint와 publicfunction에만 접근이 가능하다
Player NewPlayer = Player();
NewPlayer.SetHp(100); // Hp = 100
NewPlayer.SetHp(0); // Hp = 0
}
전역 + 지역은 합쳐서 외부라고 볼 수 있다.
// int와 class는 크게 다르지 않다...
class Player
{
};
int main()
{
int Value = int();
int& RefValue = Value;
Player NewPlayer = Player();
Plyer& RefPlayer = NewPlayer;
}
// Q1. C++에서 struct와 class의 차이는?
// Q2. C의 struct와 c++의 struct와 class의 차이는?
struct Monster
{
// 디폴트 접근제한지정자는 public이다 (1)
// 그 이외에 class와의 차이점은 없다
// 앞으로 배우게 될 모든 class 문법은 struct에도 적용된다
int Hp;
int Att;
};
int main()
{
Monster NewMonster;
// NewMonster. => 라고 치면 Hp와 Att에 접근 가능
}
/*
// C에서의 struct는 개념이 아니고, 단순한 데이터의 집합이다 (2)
// 접근제한지정자도 없다 => 모든 요소는 public처럼 취급된다
// 내부에 함수도 작성할 수 없다
struct _Monster
{
int Value;
};
typedef struct _Monster Monster;
typedef struct _Player
{
int Value;
} Player;
int main()
{
Monster NewMonster;
NewMonster.Value;
}
*/
멤버에 접근하려면 무조건 객체가 필요하다!
.
라는 멤버접근연산자를 사용해서 멤버변수와 멤버함수에 접근할 수 있다.
class Player
{
public:
int Hp; // 멤버변수
void Damage() // 멤버함수
{
}
};
int main()
{
Player NewPlayer = Player();
NewPlayer.Damage();
NewPlayer.Hp;
}
객체를 만드는 함수
멤버함수... 이지만 멤버함수의 규칙에 따르지 않는다.
// 전역
int GlobalVar = 10; // 전역변수
class Monster
{
// 멤버
private:
int Hp = 20; // 멤버변수
// 리터럴 초기화 (1)
};
class Player
{
public:
int Hp;
};
class NPC
{
public:
// 생성자
NPC() : Hp(10), Att(10) // 초기화 => 멤버 이니셜라이저 문법 (3)
{
Hp = 20; // 대입
}
private:
int Hp;
int Att;
};
class Test
{
public:
int Value = 10;
Test() :
Value(20) // 멤버 이니셜라이저 문법 (3)
// 이렇게 엔터를 쳐서 아래로 내려도 인식된다
{
}
};
int main()
{
// 지역
int LovalVar = 10; // 지역변수
Monster NewMonster = Monster(); // 지역변수
Player NewPlayer = { 10 }; // 이니셜라이즈 리스트 초기화 (2)
NPC NewNpc = NPC();
int LocalVar = int();
int Value = 0; // 초기화 : 메모리가 만들어짐과 동시에 값을 넣어준다
Value = 0; // 대입 : 메모리가 만들어진 후에 값을 넣어준다
}
초기화는 되도록 되어있는 것이 좋고, 대입과는 차이가 있다.
class의 멤버변수를 초기화하는데에는 세가지 방법이 있다.
이름이 같은데 인자가 다른 여러개의 함수를 만드는 것
void Test() // Test(void)
{
}
void Test(int _Value) // Test(int)
{
}
void Test(char _Value) // Test(char)
{
}
class Monster
{
public:
Monster() // 생성자
{
}
Monster(int _Value) // 생성자
{
}
Monster(int _Value0, int _Value1, int _Value2) // 생성자
{
}
};
int main()
{
Monster NewMonster0 = Monster();
Monster NewMonster1 = Monster(10);
Monster NewMonster2 = 10; // Monster(10)
Monster NewMonster3 = { 10 }; // Monster(10)
Monster NewMonster4 = { 10, 10, 10 }; // Monster(10, 10, 10)
}
클래스의 함수를 만들 때, 연산자 형식으로 사용할 수 있게 만드는 것
=
이 사용되곤 한다. ⇒ 중요함!class MyInt
{
private:
int Value = 0;
public:
MyInt()
// : Value(0) 로 초기화해도 된다
{
}
MyInt(int _Value)
: Value(_Value)
{
}
MyInt operator-(MyInt _Other)
{
return Value - _Other.Value;
}
};
class Player
{
public:
void operator=(const Player& _Other) // 복사
{
Hp = _Other.Hp;
Att = _Other.Att;
Def = _Other.Def;
Cri = _Other.Cri;
Exp = _Other.Exp;
Gold = _Other.Gold;
}
// 레퍼런스이므로 8byte만 사용해 빠르다
// 레퍼런스이므로 함수 바깥의 값에 실제적으로 영향을 준다
// const이기 때문에 인자의 값이 바뀔 가능성이 없다
// 레퍼런스이기 때문에 nullptr이나 비어있는 값이 인자로 들어오지 않는다 (포인터와의 차이)
int Hp;
int Att;
int Def;
int Cri;
int Exp;
int Gold;
// 보통 이런 스테이터스는 private이긴 하다...
// 직접 수정 가능해지면 곤란한 일이 생길 수 있기 때문
};
int main()
{
{
int Left = 20;
int Right = 20;
int Result = 0;
Result = Left - Right;
}
{
MyInt Left = 20;
MyInt Right = 20;
MyInt Result = 0;
Result = Left.operator-(Right); // Left - Right;
}
{
Player NewPlayer0 = { 1, 1, 1, 1, 1, 1 };
Player NewPlayer1 = { 2, 2, 2, 2, 2, 2 };
NewPlayer0.operator=(NewPlayer1); // NewPlayer0 = NewPlayer1
}
}
⇒ 포인터나 레퍼런스를 사용하지 않으면
최소 클래스의 크기만큼 사용할 뿐더러, 함수 바깥의 값이 변하지 않는다
⇒ 하지만 포인터나 레퍼런스를 사용하면
8byte만 사용하면 되고, 함수 바깥의 값에 영향을 준다
따라서 함수 호출 시 객체를 인자로 받을 때에는, 값형이 아니라 포인터 또는 레퍼런스로 받아야 한다!!!
#include <iostream>
#include <conio.h>
class Player
{
public:
Player()
{
}
void StatusRender()
{
// 멤버함수 안에서 멤버변수는 자유롭게 사용 가능하다
int Size = printf_s("%s", Name);
for (int i = 0; i < 50 - Size; i++)
{
int a = 0;
printf_s("-");
}
printf_s("\n"); // (1)
printf_s("공격력 %d\n", Att);
printf_s("체력 %d\n", Hp);
for (int i = 0; i < 50; i++)
{
printf_s("-");
}
printf_s("\n");
}
void DamageLogic(int _Att)
{
Hp -= _Att;
}
int GetAtt()
{
return Att;
}
void DamageRender()
{
printf_s("%s가 %d의 공격력으로 공격했습니다.\n", Name, Att);
}
bool IsDeath()
{
return Hp <= 0;
}
protected:
private:
char Name[100] = "Fighter";
int Hp = 100;
int Att = 10;
};
class Monster
{
public:
Monster()
{
}
void StatusRender()
{
int Size = printf_s("%s", Name);
for (int i = 0; i < 50 - Size; i++)
{
int a = 0;
printf_s("-");
}
printf_s("\n"); // (1)
printf_s("공격력 %d\n", Att);
printf_s("체력 %d\n", Hp);
for (int i = 0; i < 50; i++)
{
printf_s("-");
}
printf_s("\n");
}
void DamageLogic(int _Att)
{
Hp -= _Att;
}
int GetAtt()
{
return Att;
}
void DamageRender()
{
printf_s("%s가 %d의 공격력으로 공격했습니다.\n", Name, Att);
}
bool IsDeath()
{
return Hp <= 0;
}
protected:
private:
char Name[100] = "Orc";
int Hp = 50;
int Att = 5;
};
int main()
{
Player NewPlayer = Player();
Monster NewMonster = Monster();
while (true)
{
NewPlayer.StatusRender();
NewMonster.StatusRender();
{
int Input = _getch();
}
system("cls");
NewMonster.DamageLogic(NewPlayer.GetAtt());
NewPlayer.StatusRender();
NewMonster.StatusRender();
NewPlayer.DamageRender();
{
int Input = _getch();
}
if (NewPlayer.IsDeath() || NewMonster.IsDeath())
{
printf_s("게임 종료!\n");
break;
}
system("cls");
NewPlayer.DamageLogic(NewMonster.GetAtt());
NewPlayer.StatusRender();
NewMonster.StatusRender();
NewPlayer.DamageRender();
NewMonster.DamageRender();
{
int Input = _getch();
}
if (NewPlayer.IsDeath() || NewMonster.IsDeath())
{
printf_s("게임 종료!\n");
break;
}
system("cls");
}
}
📢 코딩스탠다드
가급적 유지하자!
- 전역변수와 지역변수는 이름을 구분하여 작성하자
- 변수에는 반드시 초기값을 설정하자
- 함수의 인자 앞에는 언더바를 붙이자
- 포인터를 초기화할 때 절대 0을 사용하지 말고, nullptr을 사용하자
- 경로, 함수명, 변수명에 한글은 절대 쓰지 말자
- 프로젝트 생성 시 바탕화면은 절대 피하자
- if문을 사용할 때, 한 줄 코드일지라도 반드시 중괄호를 사용하자
- 함수의 리턴값을 꼭 변수로 받아서 확인해보자
- 클래스를 정의하면 일단 public, protected, private 꼭 작성해두자
그리고 순서를 바꾸거나, 이후에 밑에서 한번 더 접근제한지정자를 사용하거나 하지는 말자 (new!)
📢 기억해두면 좋은 VS단축키 & 정보
- Shift + Up or Down ⇒ 한 줄 드래그
- Alt + 드래그 ⇒ 지정 사각형만큼 드래그 (+ 방향키를 누르면 커서가 다같이 움직인다)
- Ctrl + A ⇒ 문서 코드 전체 선택
- Shift + Del ⇒ 한 줄 삭제
- 드래그 + Alt + Up or Down ⇒ 윗줄 또는 아랫줄로 이동
- 드래그 + Ctrl + K+ C ⇒ 주석
- Ctrl + K + F ⇒ 자동 줄맞춤
- 파일명 위에 커서 + Ctrl + Shift + G ⇒ 파일 열기
- 이름 위에 커서 + F12 ⇒ 정의로 이동