Information Technology/C++

[C++] 첨자 연산자 오버로딩

이웃어 2019. 11. 17. 14:29

이 글은 개인의 학습을 목적으로 정리한 글입니다. 이점 참고하고 읽어주세요 ;)


C++을 비롯한 여러 언어에서 배열을 다룰 때 바로 이 '[ ]' 첨자 연산자를 다룹니다. 이번에는 사용자 정의 자료형에서도 첨자 연산자를 오버 로딩하여 사용하는 방법을 알아보겠습니다.

#include <iostream>
using namespace std;

class IntList
{
private:
	int m_list[10] = { 1,2,3,4,5,6,7,8,9,10 };

public:
	void setItem(int index, int value)
	{
		m_list[index] = value;
	}

	int getItem(int index)
	{
		return m_list[index];
	}

	int* getList()
	{
		return m_list;
	}
};

예제에서 사용할 IntList 클래스입니다.

위의 코드 블록과 같이 첨자 연산자를 오버로딩하지 않고 클래스에서 배열의 멤버에 값을 주고 또 출력하려면 setItem 함수와 getItem 함수를 설정합니다. 매개변수로 index와 value를 받는 방식입니다.

또는 배열의 이름은 곧 배열의 주소이기 때문에 int형 포인터 주소를 리턴 받는 getList 함수를 통해 m_list를 리턴할 수도 있습니다.

int main()
{
	IntList my_list;
	my_list.setItem(3, 1);
	cout << my_list.getItem(3) << endl;

	my_list.getList()[3] = 10;
	cout << my_list.getList()[3] << endl;

	return 0;
}

이를 main함수에서 사용하려면 my_list를 초기화한 다음, setItem 함수로 값을 주고, getItem함수를 통해 출력하거나,

아니면 getList 함수를 통해 my_list를 불러와서 해당 인덱스에 값을 주는 방식도 있습니다. 아무래도 int, float과 같은 자료형과 달리 이런저런 함수를 만들고 호출하는 과정이 복잡하기도 하고 중간에 실수가 생길 수도 있겠죠.

이런 과정은 클래스에 첨자 연산자를 오버로딩하면 비교적 간단하게 처리할 수 있습니다.

class IntList
{
private:
	int m_list[10];

public:
	int& operator [](const int index)
	{
		return m_list[index];
	}
};

첨자 연산자를 정의하는 방법은 다음과 같습니다.

생각해볼 점은 리턴값이 왜 int의 레퍼런스 값이냐입니다. 이는 배열의 멤버를 호출하고 또 수정하려면 그 메모리 값이 계속 존재해야 하고, 또 그 과정에서 복사가 일어나는 걸 막기 위함이라고 합니다.

이 클래스에서는 매개변수를 int 자료형으로 받았는데, 이는 클래스가 어떤 용도에 쓰이느냐에 따라 다릅니다. map 같은 경우에는 index가 string이나 char로 설정할 수 있기 때문에 상황에 알맞은 자료형을 기입하면 됩니다.

int main()
{
	IntList my_list;
	my_list[3] = 10;
	cout << my_list[10] << endl;

	return 0;
}

첨자 연산자를 정의하면 main함수에서 일반 자료형처럼 IntList 자료형의 인스턴스에 간단하게 첨자([ ])만 붙여서 배열의 값을 주고 출력도 할 수 있습니다.

const IntList my_list;
cout << my_list[10] << endl;

그런데 만약 인스턴스를 초기화할 때 값을 바꾸지 못 하게 const를 선언한 이후에 출력을 하고 싶으면 어떡해야 할까요?

그럴 땐 이전 포스팅에서 보여드린 것처럼 클래스 내에서 첨자 연산자를 정의할 때 const 선언을 해준 첨자 연산자를 설정해야 합니다.

const int& operator [](const int index) const
	{
		return m_list[index];
	}

위의 코드 블록을 클래스 내부에 리턴으로 받는 값을 변경하지 못하게 리턴 타입에도 const를 선언하고 연산자 자체에도 const를 선언하면 됩니다.


마지막으로 알아두면 좋을 점이

int& operator [](const int index)
{
	assert(index >= 0);
	assert(index < 10);

	return m_list[index];
}

헤더파일에 <cassert>를 추가하고, 첨자 연산자를 정의할 때 assert 기능을 추가하면 디버깅이나 혹시 모를 에러를 사전에 잡아줄 수 있습니다.

이번 예제에서 정의한 m_list는 크기가 10이니까 m_list의 인덱스가 0보다 작거나 같고 10보다 작을 때에만 문제없이 프로그램이 작동하고, 그 범위를 넘어서는 값이 입력되면 바로 에러가 날 수 있게 assert 기능이 잡아줍니다.