No Rules Rules

const란 (feat. c++, 오버로딩, call by value와 call by reference) 본문

언어/C++

const란 (feat. c++, 오버로딩, call by value와 call by reference)

개발하는 완두콩 2022. 7. 20. 14:01
728x90
반응형

코드 리뷰를 하거나 팀내 후배들에게 교육을 할때마다 항상 강조하는 말이 있습니다.

 

코드에 const를 덕지덕지 붙여라!

목적이 있는 변수나 함수를 선언할때는 특히나 더!

 

왜일까요? 별거 아닌거 같지만 const를 추천할까요?


const는 여러 상황에서 사용 가능합니다만 일단 순서대로 얘기해보려고 합니다.

객체의 const

우리가 일반적으로 사용하는 일반 변수에서의 const는 다음과 같은 의미를 갖습니다.

int main()
{
    int value1 = 5;             // value1이라는 녀석의 값은 5야
    value1 = 6;                 // value1이라는 녀석을 6으로 바꿀래!
    
    const int value2 = 10;      // value2라는 녀석의 값은 10이긴한데...
                                // 초기식의 값으로 유지할꺼야!
    value2 = 11;                // value2는 const 변수라서 바꿀수 없어! (에러)

    int const value3 = 20;      // value3이라는 녀석의 값은 20이긴한데...
                                // value2와 마찬가지로 초기식의 값으로 유지할꺼야!
    value3 = 21;                // value3은 onst 변수라서 바꿀수 없어! (에러)
}
 

즉, 일반 변수에서의 const 위치는 상관이 없습니다.

 

일반 변수에 * 가 붙은 포인터도 결국 포인터 변수입니다.

int main()
{
    int integer_value1 = 10;
    int integer_value2 = 20;
    
    const int* value1 = &integer_value1;    // value1은 integer_value1을 가리키는 포인터 변수!
    value1 = &integer_value2;               // value1이 가리키는 곳을 integer_value2로 변경!
    *value1 = integer_value2;               // value1이 가리키는 곳의 값을 integer_value2로 변경!
                                            // 하지만 포인터 앞의 const가 있으면 값변경 불가! (에러)
    
    int* const value2 = &integer_value1;    // value2는 integer_value1을 가리키는 포인터 변수!
    value2 = &integer_value2;               // value2가 가리키는 곳을 integer_value2로 변경!
                                            // 하지만 포인터 뒤의 const가 있으면 주소변경 불가! (에러)
    *value2 = integer_value2;               // value2가 가리키는 곳의 값을 integer_value2로 변경!
}
 

즉, 포인터 변수에서 const 존재의 핵심은

포인터 앞에 const가 붙은 포인터 변수의 경우, 해당 포인터가 가리키는 곳의 값 변경이 불가능하고

포인터 뒤에 const가 붙은 포인터 변수의 경우, 해당 포인터가 가리키는 주소 변경이 불가능합니다.

함수의 const

const를 붙여라고 강조하는 이유는 함수의 const 기능 때문입니다.

협업을 하는 경우, 다른 누군가가 정의한 함수를 사용하는 경우가 많은데 이때 const를 붙여서 해당 함수의 매개변수가 input 파라미터인지 output 파라미터인지를 명시할 수 있습니다.

 

코드로 설명을 하자면

int CalcAddFunction(const int& value1, const int& value2, int& value)
{
    value = value1 + value2;
    return 0;
}
 

위와 같이 주석이 없는 함수의 매개변수들은 그 목적을 가지고 있습니다.

value1과 value2를 합한 뒤, value에 입력하는 것입니다.

주석이 없어도 value가 대입되는 값이라는 것을 추측할 수 있는 이유는 const 존재의 유무 때문입니다. (물론 주석을 남기는게 당연히 맞겠죠.)

 

협업을 위한 이유 외에도 오류를 막기 위해 사용하기도 합니다.

class SomethingClass
{
public:
    const int& GetValue()
    {
        return m_value;
    }
    
private:
    int m_value;
};

int main()
{
    SomethingClass something;
    something.GetValue() = 10;      // const로 리턴되는 변수에 값 변경은 불가능!!(에러)
}
 

위와 같이 Getter의 목적을 갖는 메소드는 const를 붙여 외부로부터의 값 변경을 막을 수 있습니다. (const를 삭제하시면 값이 변경됩니다.)

메소드의 const
메소드 뒤에 붙는 const예용!

메소드의 후미에 붙는 const는 이런 의미를 갖습니다.

이 메소드 안에서는 멤버 변수의 변화가 일어나지 않아~~

getter에서 자주 쓰입니다.
 
int g_value = 10;

class SomethingClass
{
public:
    void SomethingToDo() const
    {
        int value;
        value = 30;         // 지역 변수는 마음껏 바꿀수 있어!
        
        g_value = 11;       // 전역 변수도 마음껏 바꿀 수 있어!
        
        m_value = 12;       // 멤버 변수는 못바꾸징~! (에러)
    }
    
private:
    int m_value;
};
 

또 이러한 const 메소드는 이러한 규칙도 갖습니다.

class SomethingClass
{
public:
    void SomethingToDo1()
    {
        
    }
    void SomethingToDo2() const
    {
        SomethingToDo1();       // const 메소드는 const 메소드만 호출 가능! (에러)
    }
    void SomethingToDo3()
    {
        SomethingToDo1();
    }
};
 

즉, 메소드의 뒤에 붙는 const 형태인 메소드는 동일한 메소드만 호출 가능하다는 점이예요.

오버로딩의 관점
const 존재의 유무에 따라 오버로딩이 가능해져요!

오버로딩은 다들 알고 계시겠죠?

오버로딩은 동일이름의 메소드지만 매개변수의 타입이나 개수 등이 달라짐으로 인해 다른 메소드로 인식합니다. 즉, 동명이인을 지칭하는 것을 의미합니다.

오버로딩/오버라이딩. 헷갈린다 이거예용~!

 

자, 그럼 const가 오버로딩과 무슨 연관이 있을까요?

#include <iostream>

class SomethingClass
{
public:
    void SomethingToDo()
    {
        std::cout << "난 const가 없어!" << std::endl;
    }
    void SomethingToDo() const
    {
        std::cout << "난 const가 있어!" << std::endl;
    }
};

int main()
{
    const SomethingClass class1;
    SomethingClass class2;
    
    class1.SomethingToDo();         // 난 const가 있어!
    class2.SomethingToDo();         // 난 constㅏ 없어!
}
 

이렇게 const 유무에 따라 오버로딩이 가능하답니다!

 

함수의 const에서 저는 함수의 매개변수마다 &를 붙였습니다.

&은 무엇이고 왜 붙였을까요?

다음은 call by value, call by reference 에 대해서 얘기해보겠습니다.

728x90
반응형
Comments