언어/C++

[C++] 상수 및 비상수 멤버 함수에서 코드 중복 현상 피하기

겜도리도리 2022. 7. 22. 01:00
반응형

개요

effective C++에서 나온 코드 중복 현상 피하기에 대해 서술한다.

예제

다음과 같이 상수, 비상수 버전의 연산자 오버로딩이 있다고 가정하자.

#include <iostream>
using namespace std;

class TextBlock
{
public:
    TextBlock(string s = "")
    {
        text = s;
    }

    const char& operator[](size_t position) const
    {
        cout << "상수 [] 호출" << endl;
        return text[position];
    }

    char& operator[](size_t position)
    {
        cout << "비상수 [] 호출" << endl;
        return text[position];
    }

private:
    string text;
};

int main(void)
{
    const TextBlock tb1 = TextBlock("test");
    TextBlock tb2 = TextBlock("Hello World");
    
    cout << tb1[0] << endl;
    cout << tb2[0];
    return 0;
}

상수, 비상수 버전에 대해 각각 연산자 오버로딩을 만들어주면 중복된 return 문이 존재하게 되고, 이는 앞으로 코드 유지 보수를 어렵게 만든다.

 

이를 해결하기 위해 비상수 버전의 연산자 오버로딩에서 상수 버전의 연산자 오버로딩을 호출해주면 된다.

#include <iostream>
using namespace std;

class TextBlock
{
public:
    TextBlock(string s = "")
    {
        text = s;
    }

    const char& operator[](size_t position) const
    {
        cout << "상수 [] 호출" << endl;
        return text[position];
    }

    char& operator[](size_t position)
    {
        cout << "비상수 [] 호출" << endl;
        return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
    }

private:
    string text;
};

int main(void)
{
    const TextBlock tb1 = TextBlock("test");
    TextBlock tb2 = TextBlock("Hello World");
    
    cout << tb1[0] << endl;
    cout << tb2[0];
    return 0;
}

tb1은 상수 객체이므로 상수 []가 바로 호출된다.

tb2는 비상수 객체이므로 비상수 []가 호출된 뒤에 상수 []가 호출된다.

 

위 코드에서 캐스팅을 두 번하는 것을 볼 수 있다.

우리가 하고 싶은 것은 비상수 []에서 상수 []를 호출하는 것인데, 비상수 []에서 operator[]라고 쓰면 자기 자신을 재귀호출하므로 문제가 발생한다.

 

따라서 static_cast를 통해 *this를 const로 캐스팅해주면 타입이 TextBlock&에서 const TextBlock&으로 바뀌고, 상수 []를 호출할 수 있다.

 

상수 []의 return값은 const char이므로 이를 다시 char로 만들어줘야 한다.

const_cast를 사용하여 이를 해결한다.

 

정리하면 다음과 같다.

1. static_cast를 통해 const를 붙여서 상수 [] 호출.

2. 상수 []의 retrun값에서 다시 const를 떼어냄.

반응형