첨자 연산자 오버로딩

Jaemyeong Lee·2024년 8월 19일
0

FastCampusC++

목록 보기
64/78

첨자 연산자 오버로딩 예제 코드 분석 및 설명

이 코드는 C++에서 첨자 연산자([])를 오버로딩하여 사용자 정의 타입을 배열처럼 접근할 수 있도록 하는 예제입니다. 여기에서는 Vector, String, HashTable 클래스를 정의하여 각각의 특성에 맞게 첨자 연산자를 오버로딩하는 방법을 보여줍니다.

1. Vector 클래스 분석

class Vector
{
public:
    float x, y, z;

    Vector(float x, float y, float z)
        : x(x), y(y), z(z)
    {

    }

    float& operator[](int index)
    {
        if (index < 1)
            return x;
        if (index < 2)
            return y;
        return z;
    }

    float operator[](int index) const
    {
        if (index < 1)
            return x;
        if (index < 2)
            return y;
        return z;
    }
};
  • 클래스 개요:

    • Vector 클래스는 3차원 벡터를 나타내며, 멤버 변수로 x, y, z를 가지고 있습니다.
    • 첨자 연산자를 오버로딩하여 Vector 객체를 배열처럼 인덱스로 접근할 수 있게 합니다.
  • 첨자 연산자 오버로딩:

    • float& operator[](int index):
      • 이 함수는 Vector 객체의 멤버 변수에 대한 참조를 반환합니다. 즉, 인덱스로 값을 읽고 쓸 수 있습니다.
      • 인덱스가 1 미만이면 x를, 2 미만이면 y를, 그 외는 z를 반환합니다.
    • float operator[](int index) const:
      • 이 함수는 const 객체에 대해 호출되며, 멤버 변수를 변경하지 않고 값을 반환합니다.
      • const 객체에서도 배열처럼 인덱스 접근을 지원합니다.

2. String 클래스 분석

class String
{
private:
    char* _chars;

public:
    String(const char* chars)
        : _chars(new char[strlen(chars) + 1])
    {
        strcpy(_chars, chars);
    }

    ~String()
    {
        delete[] _chars;
    }

    char operator[](int index) const
    {
        return _chars[index];
    }

    char& operator[](int index)
    {
        return _chars[index];
    }

    friend std::ostream& operator<<(std::ostream& os, const String& s)
    {
        os << s._chars;
        return os;
    }
};
  • 클래스 개요:

    • String 클래스는 C 스타일 문자열을 관리합니다. 동적으로 할당된 char 배열을 관리하며, 소멸자를 통해 메모리 해제를 책임집니다.
    • 첨자 연산자를 오버로딩하여 문자열의 특정 문자에 접근하거나 수정할 수 있습니다.
  • 첨자 연산자 오버로딩:

    • char operator[](int index) const:
      • const 객체에 대해 호출되며, 해당 인덱스의 문자를 반환합니다.
    • char& operator[](int index):
      • String 객체의 특정 인덱스에 있는 문자의 참조를 반환하여, 해당 문자를 수정할 수 있게 합니다.
  • 추가 연산자 오버로딩:

    • friend std::ostream& operator<<(std::ostream& os, const String& s):
      • String 객체를 출력 스트림(std::cout)에 출력할 수 있도록 지원합니다.

3. Bucket 클래스 분석

class Bucket
{
private:
    std::vector<KeyValue> _items;

public:
    Value& get(const Key& key)
    {
        for (KeyValue& keyValue : _items)
        {
            if (keyValue.first == key)
            {
                return keyValue.second;
            }
        }
        _items.push_back(std::make_pair(key, Value()));
        return _items.back().second;
    }
};
  • 클래스 개요:

    • Bucket 클래스는 키-값 쌍(Key-Value pair)을 저장하는 컨테이너로, 내부적으로 std::vector를 사용합니다.
    • get 메서드를 통해 키에 해당하는 값을 찾거나, 존재하지 않으면 새로운 키-값 쌍을 추가합니다.
  • get 메서드:

    • KeyValue는 각각 std::string으로 정의된 별칭입니다.
    • 주어진 키에 해당하는 값을 반환합니다. 만약 해당 키가 존재하지 않으면, 벡터에 새로운 키-값 쌍을 추가하고 기본 생성된 값을 반환합니다.

4. HashTable 클래스 분석

class HashTable
{
private:
    std::vector<Bucket> _buckets;

    int hash(const Key& key) const
    {
        int h = 0;
        for (char ch : key)
        {
            h += ch;
        }
        return h;
    }

public:
    HashTable(int size = 100)
        : _buckets(std::vector<Bucket>(size))
    {

    }

    Value& operator[](const Key& key)
    {
        int bucketIndex = hash(key) % _buckets.size();
        Bucket& bucket = _buckets[bucketIndex];
        return bucket.get(key);
    }
};
  • 클래스 개요:

    • HashTable 클래스는 키-값 쌍을 저장하는 해시 테이블을 구현합니다. 내부적으로 std::vector를 사용하여 버킷을 관리하며, 각 버킷은 Bucket 객체입니다.
  • 해시 함수:

    • hash 메서드는 키 문자열을 받아 해시 값을 계산합니다. 여기서는 각 문자의 ASCII 값을 더하여 해시 값을 구합니다.
  • 첨자 연산자 오버로딩:

    • Value& operator[](const Key& key):
      • 키에 해당하는 값을 찾고, 값을 반환합니다. 만약 키가 존재하지 않으면 새로운 키-값 쌍을 추가합니다.
      • Bucket을 선택하기 위해 해시 함수의 결과를 사용하며, 선택된 Bucket 객체의 get 메서드를 통해 값을 찾습니다.

첨자 연산자와 string, hashtable, vector의 관계

  • 첨자 연산자 ([]):

    • C++의 기본 타입인 배열처럼, 사용자 정의 객체도 첨자 연산자를 오버로딩하여 배열처럼 사용할 수 있습니다.
    • 이 연산자는 주어진 인덱스에 해당하는 요소를 반환하거나 수정할 수 있습니다.
  • String 클래스와 첨자 연산자:

    • String 클래스에서 첨자 연산자를 통해 문자열의 특정 문자를 읽거나 수정할 수 있습니다. 이는 C 스타일의 문자열 접근 방식과 유사합니다.
  • HashTable 클래스와 첨자 연산자:

    • HashTable 클래스에서는 키를 인덱스로 사용하여 값에 접근합니다. 해시 함수는 주어진 키를 해시값으로 변환하고, 그 값을 이용해 적절한 버킷을 선택합니다. 해당 버킷에서 키-값 쌍을 찾고, 그 값을 반환하거나 수정할 수 있게 합니다.
  • vector와 첨자 연산자:

    • C++의 std::vector는 내부적으로 첨자 연산자를 사용하여 요소에 접근합니다. Bucket 클래스에서 std::vector<KeyValue>를 사용하여 키-값 쌍을 저장하며, vector의 첨자 연산자를 활용해 해당 쌍에 접근합니다.

마무리

이 예제는 C++에서 첨자 연산자 오버로딩을 통해 사용자 정의 타입을 배열처럼 접근할 수 있도록 하는 방법을 보여줍니다. Vector, String, HashTable 클래스는 각각의 데이터 타입에 맞는 첨자 연산자 오버로딩을 통해 유연한 데이터 접근을 지원합니다. 이 기법은 클래스 객체를 더욱 직관적으로 사용할 수 있게 하며, 특히 복잡한 데이터 구조를 처리할 때 유용합니다.

블로그 포스트에서 이 내용을 정리할 때는 각 클래스의 특징과 첨자 연산자의 역할을 강조하고, 왜 이러한 설계가 필요한지를 설명하면 좋습니다. 이를 통해 독자들이 C++의 연산자 오버로딩 개념을 깊이 이해하고, 실제 코드에 적용할 수 있게 될 것입니다.

profile
李家네_공부방

0개의 댓글