본문 바로가기
Language/C++

상수 멤버함수의 설계 방법

by W00gie 2022. 3. 2.

멤버 함수에 붙는 const 키워드의 역할은 해당 멤버 함수가 상수 객체 대해 호출될 함수라는 사실을 의미한다.

이러한 함수는 먼저 클래스의 인터페이스를 이해하기 좋게하기 위해 사용되며, 두 번째로 이 키워드를 통해 상수 객체를 사용할 수 있게 하기위함이다. 

 

cosnt 키워드가 있고 없고의 차이만 있는 멤버 함수들은 오버로딩이 가능하다.  오버로드를해서 각 버전마다 반환 타입을 다르게 가져간다면 상수 객체와 비상수 객체의 쓰임새를 다르게 가져갈 수 있다. 

 

class TextBlock {
public:
	const char& operator[](std::size_t position) const
    { return text[position]; }
    
    char& operator (std::size_t poisition) 
    { return atext[position]; }
    
private:
	std::string text;
}

다만 이런식의 오버로딩을 진행하면 내부적인 코드중복을 피할 수 없다. (const 성격에 대한 처리를 제외하고는 결국 같은 내용의 코드가 진행되기 때문이다.) 이러한 코드중복을 피하기 위해서는 두번의 캐스팅을 통해서 cosnt 껍데기를 날릴 수 있다. 실제로 const 성질을 날려보내는것은 아니고, 내부적으로 비상수 버전에서 상수버전을 호출하게 만드는 형식이다. 구현방식은 다음과 같다.

 

class TextBlock {
public:
	const char& operator[] (std::size_t position) const
    {
    //...
     return text[position];
    }
	char& operator[] =(std::size_t position)
    {
    	return const_cast<char&>(
        	static_cast<const TextBlock&>(*this)[position]);
    }
    
    //....
}

1) [] 연산자의 상수버전을 호출한다.

2) *this의 타입에 const를 붙인다.

3) const 캐스팅을 통해 []연산자의 리턴타입에 const cast를 통해 const 속성을 제거한다.

 

*this의 타입 캐스팅을 통해 상수 operator를 호출한다는 점이 중요한 부분이다. 이 역순으로 상수멤버함수에서 비상수버전을 호출하게되면 컴파일러와의 내규가 깨지게되므로 위의 방식과 반대로 구현해선 안된다. 

 

 

+) const를 붙인 선언은 컴파일러가 사용상의 에러를 잡아내는데 큰 도움을 주므로 멤버함수에서의 사용도 적극적으로 하자

+)컴파일러에서 비트수준의 상수성을 지켜주지만, 코딩과정에선 개념적인 상수성을 지켜주어야한다.

+) 상수 멤버 및 비상수 멤버 함수가 기능적으로 똑같이 구현되어있을 경우 중복을 피하기 위해, 비상수 버전이 상수 버전을 호출하게 만들자

 

reference

 - Effective C++