참조자(Reference)의 이해
변수
- 할당된 메모리에 붙여진 이름
- 그 이름을 통해서 해당 메모리 공간에 접근이 가능하다
"할당된 하나의 메모리 공간에 둘 이상의 이름을 부여할 수는 없을까?"
참조자의 이해를 위해 변수 할당
int num=2020
이 상황에서 다음의 문장을 실행하면, num1이라는 이름이 붙어있는 메모리 공간에는 num2라는 이름이 하나 더 붙게 된다.
int &num2 = num1;
C에서 배웠듯이 & 연산자는 변수의 주소값을 반환하는 연산자다.
그러나 여기서 & 연산자는 전혀 다른 의미로 사용이 된다.
이미 선언된 변수의 앞에 이 연산자가 오면 주소 값을 반환을 명령하는 뜻이 되지만, 새로 선언되는 변수의 이름 앞에 등장하면, 이는 참조자의 선언을 뜻하는 게 된다.
int *ptr = &num1; // 변수 num1의 주소 값을 반환해서 포인터 ptr에 저장해라!
int &num2 = num1; // 변수 num1에 대한 참조자 num2를 선언해라!
따라서 num1의 선언 이후에 다음 문장이 실행되면,
int &num2 = num1;
num2는 num1의 '참조자'가 되며, 이는 다음의 결과로 이어진다.
결과적으로 num1이라 이름 붙어있는 메모리 공간에 num2라는 이름이 하나 더 붙은 꼴이 되었다.
"그럼 참조자도 변수??"
변수로 봐도 무리가 없다. 그 기능과 연산의 결과가 변수와 동일하다.
하지만 C++에서는 참조자와 변수를 구분해서 이야기 한다.
이미 선언된 변수를 대상으로 만들어진 num2와 같은 것을 가리켜 변수라 하지 않고, '참조자'라는 별도의 이름을 정의해 놓았다.
이어 다음의 코드를 실행하면
num2=3047;
변수 num1의 메모리 공간에 3047이 저장된다.
이렇듯 참조자는 자신이 참조하는 변수를 대신할 수 있는 또 하나의 이름인 것이다.
예제
#include <iostream>
using std::cout;
using std::endl;
int main(void) {
int num1 = 2020;
int& num2 = num1;
cout << "VAL: " << num1 << endl; // 2020
num2 = 3047;
cout << "VAL: " << num1 << endl; // 3047
cout << "REF: " << num2 << endl; // 3047
cout << "VAL: " << &num1 << endl;
cout << "REF: " << &num2 << endl;
return 0;
}
참조자는 변수를 대상으로만 선언이 가능하다.
그리고 일단 선언이 되고 나면, 변수와 차이가 없다.
주소값을 받을 수도 있고, 함수 내에 선언된 지역적 참조자는 함수를 벗어나면 소멸된다.
참조자는 별칭
"변수에 별명(별칭)을 하나 붙여주는 것입니다."
int &num2 = num1;
위의 선언에서, num1이 변수의 이름이라면, num2는 num1의 별명이라는 뜻이다.
예를 들어, 요즘 초등학생에게 잼민이라고(우리때는 초딩이었는데....) 많이 불리기 때문에
"저기 초등학생들이 있다" 라는 말과 "저기 잼민이들이 있다" 라는 말은 의미하는 바가 같다.
잼민이가 초등학생들의 참조자인 것이다.
참조자의 수에는 제한이 없으며, 참조자를 대상으로도 참조자를 선언할 수 있다.
참조자의 수에는 제한이 없다.
아래와 같이 한 변수에 대해 여러개의 참조자를 선언할 수 있다.(필요 이상의 참조자 선언은 바람직하지 않음)
int num1 = 2020;
int &num2 = num1;
int &num3 = num1;
int &num4 = num1;
참조자를 대상으로 참조자를 선언하는 것도 가능하다.(흔치는 않음)
int num1 = 2020;
int &num2 = num1;
int &num3 = num2;
int &num4 = num3;
참조자의 선언 가능 범위
참조자는 변수에 대해서면 선언이 가능하고 아래 코드들은 유효하지 않다.
int &ref = 20; // 상수를 대상 X
int &ref; // 선 선언, 후 참조 불가
int &ref=NULL; // NULL로 초기화 불가
배열 참조 예제
#include <iostream>
using std::cout;
using std::endl;
int main(void) {
int arr[3] = { 1, 3, 5 };
int& ref0 = arr[0];
int& ref1 = arr[1];
int& ref2 = arr[2];
cout << ref0 << endl;
cout << ref1 << endl;
cout << ref2 << endl;
}
배열 요소(배열이 아닌 배열의 요소)는 변수로 간주되어 참조자의 선언이 가능하다.
또한 포인터 변수도 변수이기 때문에 참조자의 선언이 가능하다.
#include <iostream>
using std::cout;
using std::endl;
int main(void)
{
int num = 12;
int* pnum = # // pnum => num 주소 / *pnum => num 값
int** dpnum = &pnum; // dpnum => pnum의 주소 /
cout << num << endl; // 12
cout << pnum << endl; // &num
cout << dpnum << endl; // &pnum
cout << *dpnum << endl; // &num
/* 아래처럼 포인터 변수도 참조자를 만들 수 있다는 내용을 참고*/
int& ref = num; // 참조자
int* (&pref) = pnum; // 포인터 변수의 참조자
int** (&dpref) = dpnum; //포인터 변수의 참조자
cout << ref << endl; // 12
cout << *pref << endl; // 12
cout << **dpref << endl; // 12
return 0;
}
참고 : [윤성우 열혈 C++ 프로그래밍] - 대부분의 내용 및 코드는 이 책에서 개인 공부 정리 목적으로 참고하였습니다.
'Language&Framework&Etc > C++' 카테고리의 다른 글
C언어 기반의 C++ 2(02-5) malloc & free를 대신하는 new & delete (0) | 2020.12.23 |
---|---|
C언어 기반의 C++ 2(02-4) 참조자(Reference)와 함수 (0) | 2020.12.22 |
C언어 기반의 C++ 2(02-2) 새로운 자료형 bool (0) | 2020.12.20 |
C언어 기반의 C++ 2(02-1) 시작에 앞서 (0) | 2020.12.20 |
C언어 기반의 C++(01-5) 이름공간(namespace)에 대한 소개 (0) | 2020.12.20 |