HOWTO · C++
C++에서 대괄호 연산자 오버로드
변경 가능한 접근과 const 접근, 선택적 인덱스 검사, 사용자 정의 자료 구조 예제를 이용해 C++ operator[]를 오버로드하는 방법을 알아봅니다.
이 페이지의 내용
C++에서 operator[]를 오버로드하려면 인덱스를 받는 멤버 함수로 선언합니다. object[index]를 통한 대입을 허용하려면 참조를 반환하고, 읽기 전용 객체를 위해 const 오버로드를 제공합니다. 이렇게 하면 사용자 정의 타입이 자체 저장 공간과 접근 규칙을 관리하면서 배열처럼 요소에 접근할 수 있습니다.
operator[]를 오버로드하는 이유와 시기
연산자 오버로딩은 클래스와 같은 사용자 정의 타입에서 연산자가 어떻게 동작할지 정의합니다. 컨테이너나 행렬을 자연스럽게 사용할 수 있게 해 줍니다. 별도의 접근자 함수를 호출하는 대신 items[index]처럼 쓸 수 있습니다. 클래스의 오버로드는 그 클래스가 포함된 식에만 영향을 줍니다. 피연산자가 내장 타입뿐인 경우 []의 동작을 바꿀 수는 없습니다.
오버로드는 operator[]라는 이름의 멤버 함수입니다. 호출자가 사용해야 한다면 public 영역에 선언합니다. 매개변수 타입은 인덱싱 방식에 맞게 정할 수 있습니다. 예를 들어 음수가 아닌 컨테이너 인덱스에는 std::size_t를 사용할 수 있습니다. 반환 타입에 따라 호출자가 선택된 요소에 어떤 작업을 할 수 있는지가 결정됩니다.
읽기와 쓰기를 위한 operator[] 구현
이 완전한 예제는 초기화된 정수 세 개를 저장합니다. 변경 가능한 객체를 위한 오버로드는 int&를 반환하므로 대입하면 선택한 요소의 값이 바뀝니다. const 객체를 위한 오버로드는 const int&를 반환하므로 해당 객체를 통해 읽은 요소를 수정할 수 없습니다.
#include <array>
#include <cstddef>
#include <iostream>
class IntList {
private:
std::array<int, 3> values{10, 20, 30};
public:
int& operator[](std::size_t index) {
return values[index];
}
const int& operator[](std::size_t index) const {
return values[index];
}
};
int main() {
IntList items;
items[1] = 25;
const IntList& view = items;
std::cout << items[1] << ' ' << view[2] << '\n';
}
25 30
프로그램은 25 30을 출력합니다. 첫 번째 식에서는 비const 오버로드가 선택되며, 이 오버로드가 참조를 반환하기 때문에 대입할 수 있습니다. const 객체에는 const 오버로드가 선택됩니다. 요소를 값으로 반환해도 읽을 수는 있지만, 대입하면 저장된 요소가 아니라 임시 값만 바뀝니다.
const 접근을 지원하고 유효하지 않은 인덱스 처리하기
앞의 예제는 std::array::operator[]를 사용하며, 이 연산에는 배열의 유효한 범위 안에 있는 인덱스가 필요합니다. 검사 없는 인덱싱은 범위를 확인하지 않습니다. 범위를 벗어난 인덱스를 사용하면 정의되지 않은 동작이 발생합니다. 사용자 정의 오버로드가 검사 없는 내부 배열이나 컨테이너를 직접 인덱싱하는 경우에도 같은 규칙이 적용됩니다.
클래스에서 인덱스를 검사하려면 저장 공간에 접근하기 전에 명시적으로 확인하고, 지원 범위를 벗어난 인덱스에는 std::out_of_range를 던지도록 구현합니다. 이 타입을 사용하려면 <stdexcept>를 포함합니다. 이는 클래스 설계에 따른 선택이며 operator[]가 자동으로 제공하는 동작이 아닙니다. 표준 라이브러리의 일반적인 방식을 따르는 컨테이너라면 operator[]는 검사 없이 두고, 별도의 검사 기능을 제공하는 접근자로 유효성을 확인할 수 있습니다.
사용자 정의 자료 구조에 operator[] 적용하기
행렬의 첫 번째 operator[]가 std::vector<int>&와 같은 행 객체를 반환하게 하면 matrix[row][column] 형태를 지원할 수 있습니다. 두 번째 []는 그 행 객체에 적용됩니다. const 행렬에는 const std::vector<int>&를 반환하는 const 오버로드를 제공하여 행과 그 요소를 읽기 전용으로 유지합니다.
연쇄 인덱싱의 각 단계는 다음 [] 연산을 지원하는 값을 반환해야 합니다. 행을 참조로 반환하면 matrix[row][column] = value와 같은 식으로 저장된 요소에 대입할 수도 있습니다. 행렬 클래스는 자체 인덱스 정책을 정해야 합니다. 검사 없이 행과 열에 접근하려면 인덱스가 유효해야 하며, 각 인덱싱 단계에 명시적인 검사를 추가할 수도 있습니다.