참조(Reference)
이미 존재하는 변수명에 또 하나의 별명을 붙여주는 문법. 즉, 변수의 별명을 지어주는 문법입니다.
int Number = 10;
int& Num = Number;
참조는 NULL 대입 불가.
포인터는 NULL 대입 가능.
int& Reference = NULL;
// 컴파일 에러.
// 참조는 반드시 존재하는 변수를 참조해야 함.
참조는 선언과 동시에 반드시 초기화.
포인터는 초기화 안해도 컴파일 가능.
int& Reference; // 컴파일 에러
참조는 참조하는 대상을 바꿀 수 없음.
Reference와 Swap() 함수
// Main.cpp
#include <iostream>
void SwapWithValue(int LHS, int RHS)
{
std::cout << "SwapWithValue() has been called." << std::endl;
int Temp = LHS;
LHS = RHS;
RHS = Temp;
}
void SwapWithPointer(int* LHS, int* RHS)
{
std::cout << "SwapWithPointer() has been called." << std::endl;
int Temp = *LHS;
*LHS = *RHS;
*RHS = Temp;
}
void SwapWithReference(int& LHS, int& RHS)
{
// Q. LHS와 RHS에 nullptr이 전달 될 수 있을까?
// Q. LHS와 RHS에도 포인터 연산이 가능할까?
std::cout << "SwapWithReference() has been called." << std::endl;
int Temp = LHS;
LHS = RHS;
RHS = Temp;
}
int main(void)
{
int A = 10, B = 20;
std::cout << "A: " << A << " // B: " << B << std::endl;
SwapWithValue(A, B);
std::cout << "A: " << A << " // B: " << B << std::endl;
SwapWithPointer(&A, &B);
std::cout << "A: " << A << " // B: " << B << std::endl;
SwapWithReference(A, B);
std::cout << "A: " << A << " // B: " << B << std::endl;
return 0;
}
// Main.cpp
struct Script
{
public:
char ScriptString[2048];
};
void Print01(Script InScript) // 아파트 한 개 호실(10톤) Vs. 집문서(10g)
{
}
void Print02(Script* InPtrToScript) // 불필요한 값 복사를 막을 수 있습니다.
{
}
void Print03(Script& InRefToScript) // 참조로도 불필요한 값 복사를 막을 수 있습니다.
{
}
int main(void)
{
Script NPC01Script = Script();
Print01(NPC01Script);
Print02(&NPC01Script);
Print03(NPC01Script);
return 0;
}
참조를 쓰는 경우와 포인터를 쓰는 경우
int* PtrToA;
int A = 10;
int& RefToA = A;
// 1. 포인터는 선언과 동시에 초기화 안해줘도됩니다.
// 참조는 선언과 동시에 무조건 초기화 해줘야합니다.
int* PtrToA = nullptr;
int& RefToA = nullptr; // 컴파일에러.
// 2. 포인터는 nullptr을 값으로 저장 할 수 있습니다.
// 참조는 nullptr을 값으로 저장 할 수 없습니다.
*(PtrToA + 1); // 너 뭐 돼?
int A = 10;
int B = 20;
int& RefToA = A;
RefToA = B; // 어떤 일이 벌어질까요?
// 3. 포인터는 "포인터 연산"이 가능합니다.
// 참조는 연산 자체가 없습니다. 다른 메모리 주소를 가르키는게 불가능합니다.
// Main.cpp
void Swap(char* InPtrToScript, const int InLength)
{
char Temp = *InPtrToScript;
*InPtrToScript = *(InPtrToScript + (InLength - 1));
*(InPtrToScript + (InLength - 1)) = Temp;
// 포인터는 연산이 가능하기에 알고리듬과 궁합이 잘맞습니다.
// ex) 문자열 뒤집기, ...
}
int main(void)
{
char String[16] = { 'a', 'b', 'c', '\0', };
Swap(String, 3);
return 0;
}
참조는 안전하지만 자유도가 떨어지고, 포인터는 안전하지 않지만 자유도가 높다.
모든 상황에서 참조를 사용하다가 필요에 따라 포인터로 변경하는 것도 좋다.
NULL 값
// Human.h
bool IsFriend(const char* InName);
bool IsFriend(int InID);
// Main.cpp
bool IsFriend = Human01->IsFriend(NULL);
// 어떤 함수가 호출될까요? IsFriend(int InID);가 호출됩니다.
// NULL의 정의를 보면, 정수 0으로 해석될 수 있는 상수이기 때문입니다.
// ex) #define NULL (0), ...
nullptr
NULL은 정수 0으로 해석될 수 있지만, nullptr은 정수로 변환되지 않도록 설계되어 있어서 포인터 상수로 사용 할 수 있다.
int Number = NULL; // compile.
int* PtrToNumber = NULL; // compile.
int AnotherNumber = nullptr; // compile error.
int* PtrToAnotherNumber = nullptr; // compile.
보통 nullptr로 쓴다.
'코딩 학습' 카테고리의 다른 글
| C++ 기초 - 객체지향 프로그래밍 (0) | 2026.03.09 |
|---|