Перегрузка оператора [] в C ++ - PullRequest
0 голосов
/ 24 февраля 2011

Я пытаюсь перегрузить оператор [] в c ++, чтобы я мог присваивать / получать значения из моей структуры данных, как словарь используется в c #:

Array ["myString"] = и т. Д.

Возможно ли это в c ++?

Я попытался перегрузить оператор, но, похоже, он не работает,

Record& MyDictionary::operator[] (string& _Key)
{
for (int i = 0; i < used; ++i)
{
    if (Records[i].Key == _Key)
    {
        return Records[i]; 
    }
}
 }

Спасибо.

Ответы [ 2 ]

5 голосов
/ 24 февраля 2011

Ваш код находится на правильном пути - вы получили правильную сигнатуру функции - но ваша логика немного ошибочна. В частности, предположим, что вы проходите этот цикл, не найдя ключ, который ищете:

for (int i = 0; i < used; ++i)
{
    if (Records[i].Key == _Key)
    {
        return Records[i]; 
    }
}

Если это происходит, ваша функция не возвращает значение, что приводит к неопределенному поведению. Так как он возвращает ссылку, это, вероятно, вызовет неприятный сбой в секунду, когда вы попытаетесь использовать ссылку.

Чтобы исправить это, вам нужно добавить некоторое поведение, чтобы вы не упали с конца функции. Один из вариантов - добавить ключ в таблицу, а затем вернуть ссылку на эту новую запись таблицы. Это поведение функции класса operator[] класса STL std::map. Другим было бы создание исключения, говорящего о том, что ключа там не было, что имеет недостаток в том, что он немного нелогичен.

В совершенно не связанной ноте я должен отметить, что с технической точки зрения, вы не должны называть параметр этой функции _Key. Стандарт C ++ гласит, что любое имя идентификатора, начинающееся с двух символов подчеркивания (т. Е. __myFunction) или одного знака подчеркивания, за которым следует заглавная буква (как в вашем примере _Key), зарезервировано реализацией для любых целей, которые они могут счесть необходимыми. , Они могут #define идентифицировать что-то бессмысленное или сделать так, чтобы он соответствовал какому-то встроенному компилятору Это может привести к тому, что ваша программа прекратит компиляцию, если вы перейдете с одной платформы на другую. Чтобы это исправить, введите K в нижнем регистре (_key) или полностью удалите подчеркивание (Key).

Надеюсь, это поможет!

0 голосов
/ 24 февраля 2011

В связанной заметке одна из проблем с operator[](const Key& key) заключается в том, что, как указывает templatetypedef, для возврата ссылки она должна быть неконстантной.

Чтобы иметь константный метод доступа, вам нужен метод, который может вернуть значение неудачного регистра. В STL это делается с помощью find() и использованием итераторов, а end() означает сбой.

Альтернативой является возвращение указателя с нулевым значением, указывающим на сбой. Это, вероятно, оправдано, если созданная по умолчанию запись не имеет смысла. Это также можно сделать с помощью оператора массива:

Record* MyDictionary::operator[] (const string& keyToFind) const
{ 

    for (int i = 0; i < used; ++i)
    {
        if (Records[i].Key == keyToFind)
        {
            return &Records[i]; 
        }
    }
    return 0;
}

Существует мнение, что operator[] должен возвращать ссылку. В этом случае вы, скорее всего, также внедрили бы find() и реализовали бы operator[] в терминах этого.

Для реализации find () вам нужно определить тип итератора. Удобный тип будет зависеть от реализации. Например, если Records [] является простым старым массивом:

typedef Record* iterator;
typedef const Record* const_iterator;
const_iterator MyDictionary::end()const
{
    return Records + used;
}
const_iterator MyDictionary::begin() const
{
    return Records;
}
const_iterator MyDictionary::find(const string& keyToFind) const
{ 
    for (iterator it = begin(); it != end(); ++it)
    {
        if (it->Key == keyToFind)
        {
            return it; 
        }
    }
    return end();
}
...