int main()
{
int value = 5;
int& ref = value;
cout << ref << endl;
ref = 10; // *ptr =10;
cout << value << " " << ref << endl;
return 0;
}
참조는 별명처럼 사용할 수 있습니다. value의 또다른 이름으로 간주하고 사용할 수 있는 것인데요.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int value = 5;
int* ptr = nullptr;
ptr = &value;
int& ref = value;
cout << &value << endl;
cout << &ref << endl;
cout << ptr << endl;
cout << &ptr << endl;
return 0;
}
포인터의 주소는 value의 주소와 똑같은 것을 볼 수 있습니다. 하지만 포인터 자체의 주소를 치면 다른 것을 볼 수 있는데요. 이것에서 포인트도 변수라는 사실을 알 수 있습니다.
int& ref;
이렇게는 불가능합니다. 참조가 별명같은 느낌인데 원래 이름이 없다면 별명도 지을 수 없겠죠? 원래 이름이 필요한 것인데요.
int main()
{
int x = 5;
int& ref = x;
const int y = 8;
int& ref = y;
return 0;
}
ref에서 y값을 바꿔버릴 수 있기 때문에 const가 있는 y는 바꿀 수 없다고 뜨면서 &ref = y는 오류가 뜨게 됩니다. 물론 const int &ref = y;를 넣으면 정상적으로 출력이 되는 것을 볼 수 있습니다.
참조가 왜 필요할까?
void doSomething(int n)
{
n = 10;
cout << "In doSomething " << n << endl;
}
int main()
{
int n = 5;
cout << n << endl;
doSomething(n);
cout << n << endl;
return 0;
}
이런 코드가 있다고 가정해봅시다. 이런 코드에서 n은 처음에 5가 출력되고 doSomething안에는 n을 10으로 해주니 n이 10이 되지만 다시 n을 출력하면 그대로 5가 됩니다.
이 이유는 doSomething() 에서는 n을 복사하는 것일 뿐 n의 값을 바꿔주는 것이 아니기 때문입니다.
그럼 우리가 n을 바꿔주는 함수를 만들고 싶을 때 어떻게 해야 할까요? 함수에서 바꿔주더라도 이런 식으로 복사하는 방식에서는 main함수에 있는 n은 바뀌지 않습니다.
void doSomething(int& n)
{
n = 10;
cout << "In doSomething " << n << endl;
}
int main()
{
int n = 5;
cout << n << endl;
doSomething(n);
cout << n << endl;
return 0;
}
이런 식으로 10으로 바뀌는 것을 볼 수 있습니다. 차이는 doSomething(int &n)을 해준 것입니다.
void doSomething(int& n)
{
cout << &n << endl;
n = 10;
cout << "In doSomething " << n << endl;
}
int main()
{
int n = 5;
cout << &n << endl;
doSomething(n);
cout << n << endl;
return 0;
}
void doSomething과 main함수에 있는 n의 주소를 보면 주소가 같은 것을 볼 수 있습니다. 포인터의 경우에는 넘겨주고자 하는 변수의 주소를 그대로 복사해서 넣어주는 것이어서 포인터는 주소가 다르지만 reference를 쓰게 되면 변수 자체가 넘어가기 때문에 주소가 같습니다.
이래서 엄청 편리하고 performance 측면에서도 참조를 넣을 때는 변수 자체가 넘어가기 때문에 복사할 필요가 없어서 효율이 더 높습니다.
참조가 유용한 경우
struct Something
{
int v1;
float v2;
};
struct Other
{
Something st;
};
int main()
{
Other ot;
ot.st.v1 = 1.0;
return 0;
}
이럴 경우 이름이 길어질 경우 복잡한데요. 이때 참조를 쓸 수 있습니다.
struct Something
{
int v1;
float v2;
};
struct Other
{
Something st;
};
int main()
{
Other ot;
int& v1 = ot.st.v1;
v1 = 1;
return 0;
}
이렇게 써줄 수 있는 것입니다. 우리가 코딩을 할 때 ot.st.v1 을 계속 쳐주려면 너무 번거로운 작업입니다. 특히 실전에서는 너무 번거로운 일인데 이렇게 참조를 해주면 v1만 쓰면 되기 때문에 코드가 훨씬 수월해집니다.
int main()
{
int value = 5;
int* const ptr = &value;
int& ref = value;
*ptr = 10;
ref = 10;
return 0;
}
이 두가지가 동일하게 작동합니다.
ptr에 *을 써서 해주는 것과 value에 &ref을 해주는 것은 둘 다 주소를 가져오는 것이기 때문에 동일하지만 그 과정이 조금 차이가 있는 것입니다.
'IT 프로그래밍 > 객체지향프로그래밍' 카테고리의 다른 글
[c++] Generic 프로그래밍과 Template (0) | 2024.05.29 |
---|---|
[C++] 상속이란? (0) | 2024.05.24 |
[따배시 6.12] 동적 할당 배열 (0) | 2024.05.17 |
[따배시 6.11] 메모리 동적할당 new 와 delete, 메모리누수 (0) | 2024.05.17 |
[따배시 8.4] 생성자 멤버 초기화 목록 (0) | 2024.05.15 |