포인터는 잘못 사용할 확률이 높고, 참조자의 활용일 상대적으로 포인터의 활용보다 쉽기 때문에, 참조자 기반의 함수 정의가 더 좋은 선택이라고 생각할 수 있습니다. 그러나 참조자 기반의 함수 정의에 좋은 점만 있는 것은 아닙니다. 


int num = 24;

HappyFunc(num);

cout << num << endl;


C언어의 관점에서는 100% 24가 출력됩니다. 그런 C++에서는 얼마가 출력될지 알 수 없습니다. 함수가 다음과 같이 정의 되어 있다면 24가 출력되겠지만,


void HappyFunc(int prm) {...}


다음과 같이 정의되어 있다면, 참조자를 이용해서 num에 저장된 값을 변경할 수도 있는 일입니다.


void HappyFunc(int &ref) {...}


이는 분명히 참조자의 단점이 됩니다. 예를 들어서 코드를 분석하는 과정에 있다면, 함수의 호출문장만 보고도 함수의 특성을 어느 정도 판단할 수 있어야 합니다. 그러나 참조자를 사용하는 경우, 함수의 원형을 확인해야 하고, 확인결과 참조자가 매개변수의 선언에 와있다면, 함수의 몸체까지 문장 단위로 확인을 해서 참조자를 통한 값의 변경이 일어나는지를 확인해야 합니다.


그렇다면, 이러한 단점을 어떻게 해결하면 좋을까요? 사실 완벽한 해결은 불가능합니다. C++에서는 최소한 함수의 원형은 확인해야 합니다. 따라서 완벽한 해결을 원한다면, 참조자 기반의 함수정의를 하지 말아야 합니다. 그러나 const 키워드를 이용하면, 이러한 단점을 어느 정도는 극복할 수 있습니다.


void HappyFunc(const int &ref) {...}


참조자 ref에 const 선언이 추가되었습니다. 이는 "함수 HappyFunc 내에서 참조자 ref를 이용한 값의 변경은 하지 않겠다!"라는 의미를 지닙니다.


여기서의 const 선언으로 인해서, 참조자 ref에 값을 저장하는 경우 컴파일 에러가 발생합니다. 따라서 함수 내에서 값의 변경이 이뤄지지 않음을 확신할 수 있습니다.  따라서 다음의 원칙을 정하고 가급적 이 원칙을 지켜주는 것이 좋습니다.


"함수 내에서, 참조자를 통한 값의 변경을 진행하지 않을 경우, 참조자를 const로 선언해서, 함수의 원형만 봐도 값의 변경이 이뤄지지 않음을 알 수 있게 한다"



const 참조자의 또 다른 특징


const int num = 20;

int &ref = num;

ref+=10;

cout << num << endl;


const 선언을 통해 변수 num을 상수화했는데, 참조자 ref를 통해서 값을 변경한다? 이것을 허용한다면 사실상 변수 num의 상수화는 의미가 없습니다. 상수화되었다면 어떠한 경로를 통하더라도 값의 변경을 허용하면 안됩니다. 다행히도 C++에서는 이를 허용하지 않습니다. 위의 코드 중 다음 문장에서 컴파일 에러를 일으키기 때문입니다.


int &ref = num;


따라서 변수 num과 같이 상수화된 변수에 대한 참조자 선언은 다음과 같이 해야 합니다.


const int num = 20;

const int &ref = num;


이렇게 선언이 되면 ref를 통한 값의 변경이 불가능하기 때문에 상수화에 대한 논리적인 문제점은 발생하지 않습니다. 그리고 const 참조자는 다음과 같이 상수도 참조가 가능합니다.


const int &ref = 50;


50 같은 프로그램상에서 표현되는 숫자를 가리켜 '리터럴(literal)' 또는 '리터럴 상수(literal constant)'라 합니다. 그리고 이들은 다음의 특징을 지닙니다.


"임시적으로 존재하는 값이다. 다음 행으로 넘어가면 존재하지 않는 상수다."


위의 코드는 숫자 50이 메모리 공간에 계속 남아있을 때에나 성립이 가능한 문장입니다. 그래서 C++에서는 위의 문장이 성립할 수 있도록, const 참조자를 이용해서 상수를 참조할 때 '임시변수'라는 것을 만듭니다. 그리고 이 장소에 상수 50을 저장하고선 참조자가 이를 참조하게끔 합니다.


임시로 생성한 변수를 상수화하여 이를 참조자가 참조하게끔 하는 구조이니, 결과적으로는 상수화된 변수를 참조하는 형태가 됩니다.


int Adder(const int &num1, const int &num2)

{

return num1 + num2;

}


위와 같이 정의된 함수에 인자의 전달을 목적으로 변수를 선언하는 것은 매우 번거로운 일이 아닐 수 없습니다.


int num1 = 3;

int num2 = 4;


이런식으로 말입니다. 그러나 임시변수의 생성을 통한 const 참조자의 상수 참조를 허용함으로써, 위의 함수는 다음과 같이 매우 간단한 호출이 가능해졌습니다.


cout << Adder(3, 4) << endl;



출처

  • 열혈 C++ 프로그래밍


+ Recent posts