Chapter1 Class
고지식한 객체지향언어 C#
// 모든길은 클래스로 통한다.
class Monster {
}
Chapter2 NameSpace
// 네임스페이스는 개념의 분류, 클래스들을 만들때 중복문제 등을 피하기 위해 namespace를 지정해서 분류
// A, B 2명의 프로그래머가 있다.
// 두 프로그래머 모두 Potion이라는 동일한 이름의 클래스를 선언했지만, NameSpace의 구분으로 인해 중복오류가 나지않는다.
namespace Aworld {
// A 프로그래머
class Potion
{
}
}
// B 프로그래머
class Potion
{
}
namespace _02NameSpace
{
class Program
{
static void Main(string[] args)
{
}
}
}
Chapter3 코드 읽는법, 디버깅 하는법 (Visual Studio -> F10)
// 코드를 짤 때 고민을 하고, 문제 해결을 하는것은 디버깅으로 눈으로 보면서 하자.
namespace codeReadingStudy
{
class Program
{
// Main을 만나는순간, OS가 코드를 읽기 시작하고, 실행이 시작된다.
static void Main(string[] args)
{
// 항상 디버깅이 중요하다.
// 비쥬얼 스튜디오 에서는 F10을 이용하여 한줄 한줄 디버깅 가능
Console.WriteLine("하하");
Console.WriteLine("하하");
Console.WriteLine("히히");
}
}
}
Chapter4 멤버변수 - 클래스 내부에 있어서 멤버변수
namespace _04MemberVar
{
class Program
{
// 선언을 함과 동시에 초기화하는 것 : 리터럴 초기화
// 코드를 실행한다는 것은 하드디스크에 있던 exe가 램에 올라가게 (복사) 되는것
// 무조건 공간을 차지한다. (메모리를 쓰는것)
// 즉 변수의 선언은
// 램에 30번지(주소값)에 4바이트만큼의(int형은 4바이트) 공간을 만들어(메모리를 차지한다) 400 값을 넣는것.
int Att = 400;
}
}
Chapter5 멤버함수
// 어떤 목적으로 만들고, 어떤 속성이 필요한지를 생각하며 만들고 쓰는것에 익숙해져야 한다.
// 주인공이 있다. Player라는 클래스를 만들었다.
class Player
{
// 주인공은 공격력이 있다. 멤버변수를 만들었다.
int ATT;
int HP;
// 이런 명사만으로는 부족해
// 행동이 필요하다. 함수를 만들자.
// 주인공은 HP로 움직일 수 있다. Move멤버함수를 만들었다.
void Move()
{
// 어떤 내용이 들어갈지 보다 어떤 쓰임으로 만들지가 우선
}
// 주인공은 ATT로 공격할 수 있다. Attack 멤버함수를 만들었다.
void Attack()
{
}
}
Chapter6 지역변수
class Player
{
// 멤버변수 - 클래스 내부에 있어서 멤버변수
int Att = 0;
int Hp;
void Fight()
{
// 선언되는 순간 지역변수는 메모리화
int Damage = 0;
Console.WriteLine("플레이어가 싸운다.");
}
}
namespace _06LocalVar
{
// c#은 프로그램의 시작조차도 클래스 안에 묶어놔야한다.. 고지식한 언어다..
class Program
{
// 시작용 함수
static void Main(string[] args)
{
// 함수 안에 있는 녀석 : 지역변수
// 지역변수 규칙 : 내부에서만 사용가능
// 실행하고자 하는 내용
// 객체화라고 하는 중요한 작업
// Player의 설계대로 플레이어를 만드는데, 그 이름을 NewPlayer1 라고 해라.
/* Player NewPlayer1 = new Player();
Player NewPlayer2 = new Player();*/
}
}
}
Chapter7 클래스 접근
class Player
{ // -> Player라는 이름의 클래스 내부
// 객체지향의 캡슐화, 은닉화
// 접근제한 지정자.
// 클래스 안에 모든걸 공개하지 않고, 필요한것만 공개.
public int HP; // 외부에도 공개
protected int ATT; // 자식에게만 공개
private int DEF; // 내부에만 공개, 접근제한 지정자 생략시 기본값은 private
public void Fight()
{
Console.WriteLine("싸운다.");
}
}
// -> 여기서부턴 클래스의 외부
namespace _07ClassAccess
{
class Program
{
static void Main(string[] args)
{
Player NewPlayer = new Player();
// 선언은 이렇게
// 위에서 만들어진 Player 객체의 내용을 사용하기 위해서는
// 객체의 이름 . 을 사용해서 접근
// 접근제한지정자가 public이 아닌경우, 외부인 요기에서는 사용못한다.
// 접근해서 사용은 이렇게.
NewPlayer.HP = 0;
NewPlayer.Fight();
}
}
}
Chapter8 함수의 선언, 함수의 사용, 함수를 사용하는 이유
namespace _08FuncEx
{
class Player
{
// 접근제한지정자 쓰지 않으면 default 는 private
// 일반적으로 외부에서 멤버변수에 접근하지 못하는게 좋다.
// 접근이 가능하면 어떤 오류가 발생할지..
int AT;
int HP;
private int LV = 1;
// 플레이어 레벨이 얼마인지 알고 싶다.
// 인자값이 아니라
// return 값을 사용해보자.
// 리턴값이란 객체가 자신의 상태를 외부에 알려주는 용도
// 외부에 알려줘야 하기 때문에 알리는 순간 함수는 끝.
// 즉, return 을 만나면 함수종료
public int GetLv()
{
return LV;
}
public void SetHP(int _HP)
{
HP = _HP;
}
// 함수는 보통 선언과 , 내용으로 나뉨
// void(리턴값) Func[이름 혹은 식별자]()[인자값]
// 인자값에는 외부에서 한개의 int 값을 _Dmg라는 이름으로 넣어주겠다.
public void Damage1(int _Dmg)
{
HP = HP - _Dmg;
}
// 인자값의 개수는 상관없다.
public void Damage2(int _Dmg, int _SubDmg)
{
HP = HP - _Dmg;
HP = HP - _SubDmg;
}
// public int 로 바꾸어야 오류가 안남. int 형이기 때문
public void DamageTOHPReturn(int _Dmg)
{
HP = HP - _Dmg;
// 리턴값은 자신이 리턴해주려는 자료형과
// 동일한 자료형이어야 한다.
return HP;
}
// 함수란 보통 클래스 외부와의 소통을위해 만든다.
}
class Program
{
static void Main(string[] args)
{
Player NewPlayer = new Player();
// NewPlayer.HP = 0;
/* 멤버 변수에 직접 접근가능하게 했다가 내가 만들 플레이어가 죽어버릴 수 있음 ㅇ.ㅇ
(어떤 오류가 발생할지 모른다는것..) */
// 함수를 사용해서 세팅할경우
// 디버깅이 가능해지고
// HP가 100이되는순간, 10이 되는순간 등.. 체크가 가능해진다.
// 그래서 멤버변수 자체를 접근해서 건드는게 아니라, 함수를 사용하는것이다.
// 외부의 값을 받아서 객체가 내부의 상태를 변화시키기위해 함수를 선언하는 경우가 많다.
NewPlayer.SetHP(200);
NewPlayer.Damage1(10);
NewPlayer.Damage2(10, 20);
NewPlayer.GetLv();
}
}
}
Chapter9 연산자
namespace _09Operator
{
class Program
{
static void Main(string[] args)
{
// = 대입 연산자. 변수에 값을 대입
int Result = 0;
int Left = 3;
int Right = 7;
// 산술연산자, 주의할점 : 나누기와 나머지는 0을 넣으면 안됨 -> 제로디비전
// + - * / %
// bool 논리 연산자
// 참과 거짓을 연산한다.
bool BResult = true;
BResult = !true; // 논리연산의 반대를 반환한다. true면 false를, false면 true
BResult = true && false; // AND : 둘 다 true일때만 true
BResult = true || false; // OR : 둘 중 하나만 true여도 true
BResult = true ^ false; // XOR : 양쪽이 다르면 true, 같으면 false
// 축약 연산자
Result = 0;
// 아래 두 코드는 동일하다.
// 산술 연산자면(/= , *=) 모두 축약 가능
Result = Result + 10;
Result += 10;
}
}
}
Chapter10 Memory(Func)
// 메모리는 모든 프로그램의 근간이 되는 개념 (C#만을 위한 공부가 아님)
// 모든 프로그램은 메모리를 사용한다.
class Player
{
}
class Program
{
static void Main(string[] args)
{
// 객체를 만들었다 -> 메모리를 지불(사용)했다.
Player Player01 = new Player();
// 메모리 크기는 선언된 지역변수 + a로 계산되는데
// 최소한 지역변수를 다 포함할 수 있는 크기만큼 메모리화 되어서 스택에 쌓인다.
// 함수의 인자값은 지역변수
// 지역변수의 특징 : 함수가 끝나면 사라진다.
}
}
Chapter11 Memory(value)
class Player
{
int AT;
int HP;
public int Test (int _Dmg)
{
// 이 안에 지역변수에서 벌어지는 일은
// 안에서의 일뿐. 메모리에 변화가 없다.
_Dmg = 1000;
// return _Dmg;
}
}
namespace _11Memory00_Value_
{
class Program
{
static void Main(string[] args)
{
Player NewPlayer = new Player();
// 함수의 인자값
int value = 0;
NewPlayer.Test(value);
// 함수가 실행된 후 value는 몇이 됐을까? 0일까 1000 일까!
// 0이 나온다.
Console.WriteLine(value);
// main의 위치 : 98(임시로 이쯤 있다고 생각)
// main의 위치에 있는 value의 값 : 0
// Test의 위치 : 74
// Test의 위치에 있는 _Dmg의 값 : 0(★98바이트에 있는 100을 받는다.)
// 해당 함수 내에서 값이 바뀌어도 value와는 아무 상관없다~ (별개의 지역변수)
// 함수 내에서 지역변수를 아무리지지고 볶아도 외부로 보내주지 않으면 안된다...
// Test함수가 끝나면 지역변수는 메모리에서 지워진다.
// 즉 value의 값은 변하지않으니까 0이다.
// return을 사용한다면! 그제서야 value가 1000으로 변할 수 있다.
value = NewPlayer.Test(value); // 값형의 처리
/* 다시정리 */
// 변수는 메모리 구조에서 스택(Stack)에 할당(Push)된다.
// 스택에는 지역변수, 함수의 복귀주소, 매개변수 등이 저장되고, 생성된 블록 내에서만 유효하다.
// 즉, 함수가 종료되거나 블럭이 닫히면 스택에서 제거(pop)된다.
}
}
}
Chapter12 Memory 메모리 구조 / call-by-value / call-by-reference
// c#의 메모리 구조는 c, c++과는 달리 CLR을 기반으로 처리한다.
// 즉, c#으로 만든 프로그램들은 .net에 의해 작동 되기 때문에 clr이 관리하는 메모리 공간을 사용한다.
// 이 메모내용은 C#의 메모리 구조 설명보다는
// 프로세스의 메모리구조와 call-by-value, call-by-reference의 설명이라 보면된다.
// call by Value(값 전달) - 값에 의한 호출, 함수에 매개 변수의 내용물을 전달 하여 복사해서 사용 하는 방식이다.
// call by Address, Call by Reference (주소 전달)
class Player
{
public int AT = 10;
public int HP = 100;
// 함수에 매개변수로 class를 넣을 수 있다.
// 클래스가 객체화 되었다. = 레퍼런스형
public void ATT(Monster _Monster)
{
_Monster.HP -= AT;
// 레퍼런스는 힙에 생선된 메모리의 위치를 가리킨다.
// 즉, 레퍼런스 값은 어느 위치를 가리키기 때문에, 그 위치(힙에 생성된)에서 값이 변경되면
// 90으로 변경된 채로 출력되는것이다.
// Player NewPlayer -> 스택영역에 생성
// new Player() -> 힙 영역에 생성
}
}
class Monster
{
public int AT = 10;
public int HP = 100;
public void ATT(Player _Player)
{
_Player.HP -= AT;
// 플레이어의 HP를 몬스터의 공격력만큼 깎음(-)
// 플레이어의 HP = 90이됨.
}
}
namespace _12Memory02_Reference_
{
class Program
{
static void Main(string[] args)
{
Player NewPlayer = new Player();
Monster NewMonster = new Monster();
// * 레퍼런스형
NewMonster.ATT(NewPlayer);
// 몬스터가 공격을 했다. Player의 HP가 90으로 변경되었다! -> 레퍼런스형이어서 가능한일
NewPlayer.ATT(NewMonster);
// 플레이어가 공격을 했다. Monster의 HP가 90으로 변경되었다! -> 레퍼런스형이어서 가능한일
// 전 강의에서 배운대로라면, return 하지않으면 안바뀌어야 하는것 아닌가?
// 오해의 소지가 있다. 바뀌는게 정상이다.
// 클래스가 객체화된 녀석 (ex_ NewMonster.ATT(NewPlayer))은 레퍼런스 형이라고 하는 자료형이 되고
// 지금까지 사용한 int, bool 이런 녀석들은 값형 이라고 한다.
// 값형과 레퍼런스형은
// 메모리의 위치와 사용법이 다르기 때문에 다르게 동작한다.
// 값형과 레퍼런스형을 구분해야 한다.
// 값형 : 기본자료형을 선언만 한것
// 레퍼런스형 : 클래스를 nwe 클래스명(클래스명); 해서 만든 클래스 객체
/* 힙이란 ?
* 메모리 구조에는 힙(Heap)이 있는데, 실행시간(run time)중에 동적으로 할당된 변수들이 저장되는 공간.
* new 클래스명(); 해서 만들어진 클래스 객체들의 본체가 위치한 곳
* 프로그래머가 직접 new와 delete 연산자를 사용해서 메모리의 할당과 해제를 관여하는 곳이지요.
*/
// 스택이란?
// 함수의 실행 메모리 영역, (그 박스 안에 들어있는 지역변수)이 저장됐다가 종료되며 사라지는 공간
}
}
}
Chapter13 정적 멤버변수 static
class Player
{
// static : 정적 멤버변수
// - 일반적인 멤버변수와 다른점
// 정적 멤버변수는 객체화를 하지 않고도 사용가능
// 사용법이 클래스의 이름만으로 사용 가능
// 사용법 : 클래스.정적멤버변수명
public static int PlayerCount = 0; //정적 멤버변수의 선언
public int AT = 10; // 일반 멤버변수
public int HP = 100; // 일반 멤버변수
public void Setting(int _AT, int _HP)
{
AT = _AT;
HP = _HP;
}
}
// 몬스터 100마리가 죽으면 이벤트 발생하고 싶다
class Monster
{
// int MonsterDeathCount; // 공통으로 쓰일 통계값이니까 3번이나 생성할 필요 없다.
// 수정
static int MonsterDeathCount; // 그래서 static으로 선언했다.
public void Death()
{
MonsterDeathCount += 1;
}
}
class SidePlayer
{
// 정적 멤버변수는 객체 귀속이 아니라, class에 귀속되고, 데이터 영역에 메모리가 올라간다.
static public int PlayerCount;
// static이 붙지 않은 멤버변수들은 멤버변수라고 불리며
// 객체 하나하나가 따로 사용한다.
public int x = 0;
}
namespace _13StaticVar
{
class Program
{
static void Main(string[] args)
{
Player newPlayer1 = new Player();
Player.PlayerCount += 1; // newplayer 를 생성할때마다 PlayerCount를 증가시키고 싶어!
Player newPlayer2 = new Player();
Player.PlayerCount += 1; // newplayer 를 생성할때마다 PlayerCount를 증가시키고 싶어!
Player newPlayer3 = new Player();
Player.PlayerCount += 1; // newplayer 를 생성할때마다 PlayerCount를 증가시키고 싶어!
// static인 PlayerCount는 객체화 하지 않고도 클래스명으로 접근(.) 하여 사용 하는걸 볼 수있다.
// 정적 멤버변수는 데이터 영역에 들어가기 때문이다.
// 정적 멤버 변수는 클래스가 공유하고 싶은 값
// 예를 들어 Monster 클래스안에 모든 몬스터의 수를 공유하고 싶다면? 그것을 static 선언하여 사용하자.
// 즉 하나의 클래스 내에 모든 객체가 공유하는 변수 = static, 정적 멤버변수
PlayerCount 변수를 static으로 선언하지 않으면 어떻게 될까?
위의 예제로 보자면, 클래스 내에 선언된 객체(newPlayer1, newPlayer2, newPlayer3)마다
PlayerCount라는 변수를 따로 사용하게 되고, 처음 원하던 통계값인 3이 아니라
각각 PlayerCount = 1 꼴로 데이터가 담기게 된다.
newPlayer1.Setting(10, 100);
newPlayer2.Setting(20, 50);
newPlayer3.Setting(100, 500);
Monster NewMonster1 = new Monster();
Monster NewMonster2 = new Monster();
Monster NewMonster3 = new Monster();
NewMonster1.Death(); // 1
NewMonster2.Death(); // 1
NewMonster3.Death(); // 1
// 몬스터 1, 몬스터2, 몬스터3 세마리 죽었다. but MonsterDeathCount는 모두 1.
// static으로 선언하면 의도한대로 MonsterDeathCount는 3
// ★ static : 모든 객체가 값을 공유할 필요가 있는 데이터를 정의하는데 사용한다.
}
}
}