C에서 const상수화와 관련있다. C++도 마찬가지이다. 다음의 예를 보자.
//c
int val = 5;
const int num = 3; //num의 값 변경 불가
const int* ptr = &val; //포인터 변수 ptr로 val의 값 변경 불가
int* const ptr = &val; //포인터 변수 ptr의 '값' 변경 불가
const int* const ptr = &val; //포인터 변수 ptr이 가리키는 변수값 변경 불가, ptr의 '값'변경 불가
이렇게 정리할 수 있다.
c++에서 추가된 reference는 해당 변수를 '참조'한다. 예시를 보자.
int num = 3;
int &ref = num;
ref = 4;
cout << num << endl;
//결과 4
ref는 num을 참조한다. num이 가리키는 메모리 공간의 이름이 하나 더 생겼다고 생각하면 된다.
reference는 우항에 변수가 와야한다. 상수가 오면 곤란한 상황이 연출되는데 예시를 보자.
int &ref = 30;
30은 리터럴 상수이다. 위의 상황이 가능하다면
ref = 24;
다음과 같이 리터럴 값을 바꿔버리는 대참사가 일어나게 된다.
따라서 기본적으로는 상수를 참조하는 것은 막고 있다. 하지만 다음과 같은 상황은 또 허용하는데,
const int& ref = 30;
const와 reference가 합쳐졌다. 위의 const의 의미는 ref가 가리키는 값은 변경하지 않겠다는 의미가 되며, 최종적으로는 ref가 가리키는 30을 바꾸지 않겠다는 의미가 되어 이것은 허용한다. (사실 더 구체적으로 들어가면 임시변수를 생성하고 그 임시변수(const 변수이다.) 값을 30으로 세팅하며 위의 ref는 그 임시 변수값을 가리키는 것이 된다.)
다음이 허용되면서 밑의 예시가 가능해진다.
int add(const int &a, const int &b){
return a+b;
}
cout << add(1,2) << endl;
참조자지만 상수를 넘겨줄 수 있게 된다.
이번엔 반환형이 ref인 함수를 봐보자.
int &A(int &a){
a++;
return a;
}
int main(){
int num = 4;
int &b = A(num);
int c = A(num);
num++;
cout << b << endl;
cout << c << endl;
return 0;
}
다음의 결과값이 어떻게 될까?
요즘 복잡하지만 설명하자면 다음과 같다.
int main(){
int num = 4;
int &b = A(num); //num의 값이 5가 되고 이것이 b에게 전달. b는 num을 참조
int c = A(num); //num의 값이 6이 되고 이것이 c에게 전달.
//'c는 단순히 6의 "값"만 넘겨 받음.'
num++; //num이 증가함에 따라 b도 같이 증가. c는 변화없음
cout << b << endl; //7
cout << c << endl; //6
return 0;
}
참조자가 반환형인 함수는 이렇게 그 값이 참조형에 담기냐, 일반형에 담기냐에 따라 다른 결과가 도출된다.
마지막으로 포인터, 참조자, const를 짬뽕해보자.
int main() {
int num = 3;
int *ptr = #
int *(&ptr2) = ptr;
*ptr2 = 4;
cout << num << endl;
return 0;
}
먼저 다음을 살펴보자. 결과값은 4가 나온다. reference로 포인터 값도 참조할 수 있다는 것을 보여주는 예시이다.
int main() {
const int num = 3;
const int * const ptr = #
int * const(&ptr2) = ptr;
*ptr2 = 4;
cout << num << endl;
return 0;
}
위의 식에서 오류는 어느 부분에서 발생할까?
정답은 *ptr2 = 4에서 발생한다. ptr이
const int* const
형이 므로 그 안의 속한 값을 변경할 수 없는데
int *const
형인 ptr참조자가 그 값을 바꾸려고 시도했기 때문이다.
(int *const는 가리키고 있는 주소의 값을 변경할 수 있다.
그리고 애초에 const int num이라 값을 바꿀 수가 없었다.)
int main(){
const int num = 3;
int * const ptr = #
int * const(&ptr2) = ptr;
*ptr2 = 4;
cout << num << endl;
return 0;
}
위의 예시도 당연히 오류가 된다.
int main() {
int num = 3;
int num2 = 5;
int *ptr = #
int *const(&ptr2) = ptr;
int *newptr = &num2;
*ptr2 = 4;
ptr2 = newptr;
ptr = &num2;
cout << *ptr2 << endl;
return 0;
}
ptr2 = newptr;
를 하면 ptr2가 가지고있는 값을 바꿔버려 오류가 발생한다. 그것을 제거하면
위의 예시에선 ptr = &num2;을 통해 간접적으로 ptr2이 가리키는 값을 바꿔버렸다.
따라서 결과값은 5가 나온다.
int main() {
int num = 3;
int num2 = 5;
int * ptr = #
int * const(&ptr2) = ptr;
const int *ptr3 = #
*ptr = 1;
cout << *ptr3 << endl;
*ptr2 = 2;
cout << *ptr3 << endl;
*ptr2 = 4;
ptr = &num2;
cout << *ptr2 << endl;
return 0;
}
이렇게 하면 결과값이 1 2 5가 나오게 된다.
(어우 복잡하다.)