형식
- C++에는 값형식, 참조형식이 없다
- C++의 클래스와 구조체의 차이는 (녹음)
- C++은 구조체 상속이 가능하다. (C#은 구조체 상속이 불가능하다)
- 데이터 위주 : 구조체를 사용한다.
- 기능 위주 : 클래스를 사용한다.
- C++은 구조체를 생성할때 중괄호 끝에 세미콜론 (;)을 붙여야한다.
struct A
{
int b;
int c;
};
A ob; //ob에는 b 공간과 c 공간이 있다.
ob.b = 10; //ㅠrhdrksdp 10dl emfdjrkTek.
A* obp = new A(); //obp는 32비크?(녹음 듣자) ,
obp -> b = 10; //obp에 저장된 주소로 b에 접근해서 10을 저장한다.(간접 접근)
// 위와 동일한 작업이다. / 밑의 작업을 '역참조'라고 한다.
(*obp).b = 10; //.이 우선순위가 더 높아서 ()를 붙여야한다.
직접 참조 연산자 (직접 접근 연산자)
- 위의 코드에서 ob.b의 ‘.’을 직접 참조 연산자 라고 한다.
구조체
- C#에서는 접근 지정자를 안붙이면 ‘public’이지만, C++은 접근지정자를 작성하지 않으면 ‘private’로 생성된다.
- obp -> b = 10; : 간접 접근
- (*obp).b = 10; : 직접 접근
- Character* character2 = new Character();
- 포인터로 동적할당을 한다면 간접 접근을 써야한다.
- 구조체안에 int가 2개니 4바이트 + 4바이트 = 8바이트다.
- Character* pArr = arr;
- 포인터 변수들은 변수명 앞에 p를붙이는 경우가 많다.
- 총 5포인트가 선언되었고 1포인트당 8바이트(4바이트 + 4바이트)다.
- 만약 주소가 0x100부터 시작한다면 그다음 주소는 0x108번지다.
private:
int Hp;
struct Character
{
int Hp;
int Mp;
};
Character character;
character.Hp = 100;
character.Mp = 50;
printf("Hp = %d, Mp = %d\\n", character.Hp, character.Mp);
Character* character2 = new Character(); //포인터로 동적할당을 한다면 간접 접근을 써야한다. / 구조체안에 int가 2개니 4바이트 + 4바이트 = 8바이트다.
character2 -> Hp = 80;
character2 -> Mp = 60;
printf("Hp = %d, Mp = %d\\n", character2 -> Hp, (*character2).Mp);
Character* character3 = &character;
character3->Hp = 200; //character의 Hp의 값이 바뀐다.
printf("Hp = %d, Mp = %d\\n", character.Hp, character.Mp);
Character arr[5];
for (int i = 0; i < 5; i++) {
arr[i].Hp = arr[i].Mp = 0;
}
arr[0].Hp = 10;
printf("arr[0] = %d\\n", arr[0].Hp);
Character* pArr = arr; //포인터 변수들은 변수명 앞에 p를붙이는 경우가 많다. / 총 5포인트가 선언되었고 1포인트당 8바이트(4바이트 + 4바이트)다. / 만약 주소가 0x100부터 시작한다면 그다음 주소는 0x108번지다.
pArr[1].Hp = 20;
printf("arr[1] = %d\\n", arr[1].Hp);
C++의 기본
- 시작주소? 뭐가였지? 녹음듣자
- 배열의 뭐의 앞에 시작주소로 시작된다. Character* pArr = arr; //→ &arr[’’]
배열
- C++에서는 배열도 ‘스택’에 할당이 가능하다.
- a[1] == (*a + 1) 이다.
- *(arr + 1) = 10;
- 자기 자료형의 크기만큼 숫자 써있는 횟수만큼 건너뛴다.
- 현재몇번쨰 자리인지 안써있으니 0번째 자리에 적용이 되고, 결과는 arr[1]의 자리에 10이 저장된다.
- (*arr + 1).Hp = 20;
- arr[1]의 주소에 접근했고 그 안에있는 Hp에 20을 넣었다.
- (arr + 2) => Hp = 20;
- 포인터를 쓰지않고 주소로 접근해서 요소에 접근할 수 없으니 '간접 접근' (⇒)을 사용해서 값을 넣었다.
int arr[5];
arr[0] = 6;
*arr = 7; //0번자리의 6이 7로 바뀐다.
*(arr + 1) = 10; //자기 자료형의 크기만큼 숫자 써있는 횟수만큼 건너뛴다.
(*arr + 1).Hp = 20; //arr[1]의 주소에 접근했고 그 안에있는 Hp에 20을 넣었다.
(arr + 2) => Hp = 20; //포인터를 쓰지않고 주소로 접근해서 요소에 접근할 수 없으니 '간접 접근'을 사용해서 값을 넣었다.
Character* pArr = arr; //포인터 변수들은 변수명 앞에 p를붙이는 경우가 많다. / 총 5포인트가 선언되었고 1포인트당 8바이트(4바이트 + 4바이트)다. / 만약 주소가 0x100부터 시작한다면 그다음 주소는 0x108번지다.
pArr[1].Hp = 20; //a[1] == (*a + 1) 이다.
printf("arr[1] = %d\\n", arr[1].Hp);
(*(pArr + 1)).Hp = 30; //.이 *보다 우선순위가 높다보니 C의 인텔리센스에서 인식이 안된다. -> *도 괄호로 묶는다.
printf("arr[2] = %d\\n", arr[2].Hp);
pArr->Hp = 40;
printf("arr[0] = %d\\n", arr[0].Hp);
(arr + 3)->Hp = 50;
printf("arr[3] = %d\\n", arr[3].Hp);
(pArr + 4)->Hp = 60;
printf("arr[4] = %d\\n", arr[4].Hp);
클래스
- 클래스는 접근 지정자를 아무것도 안쓰면 ‘private’로 자동 지정되어서 public: 으로 선언 해줘야한다.
- std::string : 문자열을 다뤄주는 클래스다.
- 이건 몇 바이트인지 모른다.(쓰는데로 늘어나기 때문이다.)
- C에서는 static을 외부 초기화를 반드시 해줘야 한다.
- Character* temp = new Character();
- 스택영역에 생성되었다. -> 이것도 4바이트 아니면 8바이트다.
- temp->Id = Character::Counting();
- C++은 ::fh zmffotmfmf wkrtjdgksek.
- ++이니 처음은 1이 들어간다.
- *character = temp;
- character는 2차 포인터다.
- 매개로 들어온 포인터에 생성된 클래스의 객체를 연결하여 반환했다. => 2차 포인터 사용 이유
- 2차 포인터에서 객체를 초기화하는 방식 / 모든 객체 초기화는 이렇게 진행한다.
- Character* player = nullptr;
- 스택에 저장된 포인터의 크기는 4바이트 아니면 8바이트다.
- Name.c_str() : c에서 간접접근으로 문자열을 출력하는 방법
- 객체가 초기화되는 순서
- Character* player = nullptr;
- player 포인터 메모리 공간이 스택에 생성된다.
- SetCharacter(&player, "Oak");
- 캐릭터 설정 함수를 플레이어 포인터 객체의 주소와 문자열을 넣고 호출한다.
- Character* temp = new Character();
- 지역 포인터 변수로 스택영역에 temp 공간이 생성된다.
- temp 포인터 변수는 새롭게 생성한 Character를 가리키는 주소를 갖고 있다.
- temp->Id = Character::Counting(); / temp->Name = name;
- ++연산이니 temp의 Id에는 1이 저장된다.
- temp의 Name에는 name이 저장된다.
- character = temp; (* 중요 **)
- 작성한 temp 포인터 변수를 매개변수로 들어온 character 이중 포인터 변수에 넣는다.
- temp에 저장된 Character 클래스 객체의 메모리 주소가 character 이중 포인터 매개변수로 넘어가고, character 이중 포인터 매개변수가 가리키는 player 포인터 변수에 다시 넘어간다.
- 결론적으로, temp에 있던 Character 클래스 객체 주소가 player 포인터 변수에 저장된다.
class Character
{
public:
int Id;
std::string Name; //std::string : 문자열을 다뤄주는 클래스다. / 이건 몇 바이트인지 모른다.(쓰는데로 늘어나기 때문이다.)
private:
static int Number; //C에서는 static을 외부 초기화를 반드시 해줘야 한다.
public:
static int Counting() {
return ++Number;
}
};
int Character::Number = 0; //외부초기화한 스테틱 변수
//이게 팩토리패턴의 기본 -> 객체 초기화를 새롭게 찍어낼 수 있기 때문이다.
void SetCharacter(Character** character, std::string name)
{
Character* temp = new Character(); //스택영역에 생성되었다. -> 이것도 4바이트 아니면 8바이트다.
temp->Id = Character::Counting(); //C++은 ::fh zmffotmfmf wkrtjdgksek. / ++이니 처음은 1이 들어간다.
temp->Name = name;
*character = temp; //character는 2차 포인터다. / 매개로 들어온 포인터에 생성된 클래스의 객체를 연결하여 반환했다. => 2차 포인터 사용 이유 / 2차 포인터에서 객체를 초기화하는 방식 / 모든 객체 초기화는 이렇게 진행한다.
}
int main()
{
Character* player = nullptr; //스택에 저장된 포인터의 크기는 4바이트 아니면 8바이트다.
SetCharacter(&player, "Oak");
printf("%d, %s\n", player -> Id, player -> Name.c_str()); //Name.c_str() : c에서 간접접근으로 문자열을 출력하는 방법
//....
Character* dwarf = nullptr; //스택에 저장된 포인터의 크기는 4바이트 아니면 8바이트다.
SetCharacter(&dwarf, "Oak");
printf("%d, %s\n", dwarf->Id, dwarf->Name.c_str()); //Name.c_str() : c에서 간접접근으로 문자열을 출력하는 바업
//.....
Character* elf = nullptr; //스택에 저장된 포인터의 크기는 4바이트 아니면 8바이트다.
SetCharacter(&elf, "Oak");
printf("%d, %s\n", elf->Id, elf->Name.c_str()); //Name.c_str() : c에서 간접접근으로 문자열을 출력하는 바업
}