C++ Rookiss Part1 C++ 프로그래밍 입문 : 참조 기초, 포인터 vs 참조 복습
🙇♀️참조 기초 복습
🪐이전까지의 방식들
struct StatInfo // 연습용 구조체
{
int hp;
int attack;
int defence;
};
void CreateMonster(StatInfo* monster) // 포인터 방식
{
monster->hp = 40;
monster->attack = 8;
monster->defence = 1;
}
void CreateMonster(StatInfo monster) // 복사 방식
{
monster.hp = 40;
monster.attack = 8;
monster.defence = 1;
}
🪐값 전달 방식
void PrintInfoByCoppy(StatInfo info)
{
cout << "HP: " << info.hp << endl;
}
PrintInfoByCoppy(monster); // 사용법
값이 복사 되는 방식이며 구조체의 크기가 매우 크다면 구조체 크기만큼 복사 되기 떄문에 부담스럽다.
값을 바꾸는 것이 아니라 읽기만 한다면 사용가능하다.
🪐주소 전달 방식
void PrintInfoByPtr(StatInfo* info)
{
cout << "HP: " << info->hp << endl;
}
PrintInfoByPtr(&monster); // 사용법
포인터를 통한 주소를 전달하는 방식이며 주소 크기인 8바이트만 사용한다는 점이 장점이다.
구조체 안 변수를 확인할 때 ->
연산자를 사용해야 한다는 것이 특징이다.
🪐참조 전달 방식
void PrintInfoByRef(StatInfo& info)
{
cout << "HP: " << info.hp << endl;
}
PrintInfoByRef(monster); // 사용법
참조 전달 방식은 &
연산자를 사용하는 것이 특징이고 사용할 때 .
을 사용한다.
로우레벨(어셈블리) 관점에서 실제 작동 방식은 int*와 똑같다.
C++ 관점에서는 number라는 바구니에 또 다른 이름을 부여한 것이다. (별칭의 개념)
int number = 1;
int& reference = number;
reference = 2;
여기서 reference를 바꾼다면 진퉁인 number를 바꾸는 것과 같다
🙇♀️포인터 vs 참조 복습
🪐포인터 vs 참조
성능적으로는 완전히 동일하다. 편의성은 참조가 더욱 편리하지만 함수를 사용시 &
을 사용하지 않기 때문에 원본 데이터를 훼손 시킬 우려가 존재한다.
void PrintInfoByRef(const StatInfo& info)
{
cout << "HP: " << info.hp << endl;
// info.hp = 10; // Error
}
PrintInfoByRef(monster); // 사용법
원본 데이터를 지키기 위해 const
를 사용하면 된다. 참조의 경우 대부분 저렇게 사용하는게 컨벤션!
#define OUT
void ChangeInfo(OUT StatInfo& info)
{
info.hp = 1000;
}
ChangeInfo(OUT info); // 사용법
문법적으로만 볼 떄 참조는 복사 형식과 똑같기 때문에 명시적으로 OUT
이라는 아무런 역할이 없는 것을 붙여서 원본을 사용한다는 것을 표시한다.
🪐포인터와 const
포인터에서 const는 *
앞과 뒤로 구분한다.
- 별 뒤에 붙인다면?
StatInfo* const info
- info라는 바구니의 내용물(주소)을 바꿀 수 없다
- info는 주소값을 갖는 바구니 -> 이 주소값이 고정이다!
- 아래 예시에서
info = &globalInfo;
가 안된다
- 별 이전에 붙인다면?
const StatInfo* info
- info가 ‘가리키고 있는’ 바구니의 내용물을 바꿀 수 없다
- ‘원격’ 바구니의 내용물(주소값의 데이터)을 바꿀 수 없다
- 아래 예시에서
info->hp = 10000;
가 안된다
StatInfo globalInfo; // 구조체 전역변수
void PrintInfoByPtr(StatInfo* info) // (const StatInfo* info) or (StatInfo* const info) or (const StatInfo* const info)
{
cout << "HP: " << info->hp << endl;
}
info = &globalInfo;
info->hp = 10000;
🪐초기화 여부
참조 타입은 바구니의 2번째 이름으로 참조하는 대상이 없으면 안된다.
포인터는 대상이 없어도 된다. -> 대상이 실존하지 않을 수도 있다
- 포인터에서 ‘없다’는 의미는 어떻게 표현?
- nullptr
StatInfo* pointer = nullptr;
처럼 사용int a = nullptr
는 에러가 발생
참조 타입은 이런 nullptr의 개념이 없다
StatInfo* pointer; // StatInfo구조체 포인터 변수
pointer = &info; // 포인터 변수에 info라는 StatInfo형 구조체 변수 주소를 넣음
// StatInfo* pointer = &info; 와 같다
PrintInfo(pointer); // PrintInfo(&info);와 같다
// StatInfo& referece; // Error! 참조는 초기화 값이 필요하다
StatInfo& reference = info;
// reference++; // Error 사칙연산 불가!
PrintInfo(reference);
🪐포인터->참조, 참조->포인터
- 포인터로 사용하던걸 참조로 넘겨주려면?
- pointer [ 주소(&info) ] ref, info [ 데이터 ] ```cpp StatInfo* pointer = &info;
StatInfo& ref = pointer; PrintInfoByRef(pointer); // PrintInfoByRef(ref);과 같음
* 참조로 사용하던걸 포인터로 넘겨주려면?
- pointer [ 주소 ] reference, info [ 데이터 ]
```cpp
StatInfo* ptr = &reference;
PrintInfoByPtr(&reference); // PrintInfoByPtr(ptr);과 같음