2013-04-22 3 views
0

У меня есть небольшая проблема с двумя операторами в моем классе.Как использовать оператор + и оператор = вместе?

Мой класс объявлен:

template <class keyType, class valueType> 
class MyMap{ 

    keyType keys[MAX]; 
    valueType values[MAX]; 
    int size; 
} 

мне нужно переопределить оператор [], например, когда я называю: std::cout<<MyMap1["a"];.

keyType& operator[] (keyType key){} 

Он отлично работает. Я использовал его для выполнения заданий, и это было хорошо, например: MyMap1["a"]="a1";

Код был идеален. Но в моем operator[] я увеличиваю параметр size, и это полезно только тогда, когда я хочу выполнить задание. Я не хочу увеличивать его, когда я делаю только std::cout.

Так может быть, я должен переопределить функцию operator=, но когда я не могу написать:

void operator=(valueType value){} 

Поскольку левая часть MyMap1["a"] = "a1" является keyType и не MyMap типа.

Как я могу это сделать?

+3

Если имеется в виду ваш класс будет K-> V отображение, то оператор [] должен быть определен как 'ValueType & оператора [] (keyType key) ', потому что, когда вы пишете' map [key] ', вы обычно хотите читать/записывать значение, хранящееся под этим заданным ключом. – quetzalcoatl

+0

Правильно! Но два типа были String, поэтому я не видел эту ошибку. Любые идеи для моей проблемы? – Apaachee

ответ

0

Вы увеличиваете size только в том случае, если key нет в keys, справа? Вот что делает std::map. Поэтому, если вы просто распечатываете содержимое карты, вы будете считывать значения для существующих ключей, поэтому size не будет увеличиваться.

+0

Вы правы, я только увеличиваю размер, когда ключа нет, и вы в два раза правы, я пытаюсь переписать класс std :: map. Но я хочу, чтобы std :: cout ключ, которого нет в моем классе, и я хочу, как вывод std :: endl – Apaachee

+0

(cut: было не так), и это самая проблема: он не хочет увеличивать его, когда он использует оператор [] для чтения. – quetzalcoatl

1

«Но в моем операторе [] я увеличиваю параметр размера».

Нельзя. Проверьте, существует ли ключ, и увеличивайте значение size только при вставке нового ключа. Когда вы делаете std::cout, предположительно вы делаете это только на существующих парах ключ/значение.

С учетом комментариев, это альтернативное решение. В operator[] верните MyMap<KeyType, ValueType>::proxy. Это обертывает MyMap& и Key. Перегрузка MyMap::proxy::operator=(ValueType) для назначения нового значения и приращения size. Перегрузка MyMap::proxy::operator ValueType() const, чтобы получить значение. Верните ValueType(), если ключа нет.

+0

Я копирую/вставляю вам тот же ответ, который я рассказал Полу, но я хочу, чтобы std :: cout ключ, которого нет в моем классе, и я хочу, как вывод, std :: endl – Apaachee

+0

@Apaachee: Edited. – MSalters

+0

Отлично, спасибо большое! – Apaachee

1

Когда вы пишете:

auto blah = map[key]; 

оператор [] вызывается с key, и она возвращает значение.

Когда вы пишете:

map[key] = blah; 

то оператор [ключ] вызывается с key, и она возвращает значение, а затем оператор = называется по значению с blah аргументом.

Это означает, что может быть трудно обнаружить, где бы вы на самом деле не читали или не писали карту.

Однако, как правило, в том случае, READ, случай может упасть обратно в value const& operator[] const называется, в то время как во время записи, было бы value& operator[]без константных маркеров. Таким образом, вы можете может попытаться перегрузить оператор по спецификатору const: предоставить 2 оператора [] s, один const, один неконстантный и увеличить размер только в последнем.

Этих простой простой, но не всегда будет работать должным образом, как вы могли бы произойти в какое-то время accidentially призывают «оператора [] для чтения», но без ограничения константного определяемого в этой точке с помощью компилятора. Я не могу сейчас точно сказать, когда и как, и если это вообще возможно, но я предполагаю, что вы можете легко ударить, если вы не очень осторожны с константой.

Если вы попали, что, то единственный вариант известный мне бы предоставить оболочку для возвращаемого значения в режиме неконстантного и оставить нормально сопзИте режим:

myMap::valueType const & operator[](key...) const 
mymap::wrapper<myMap::valueType>& operator[](key...) 

Вашей обертка будет помнить реф & на вашу карту и woudl запомните KEY, и эта оболочка предоставит неявное преобразование-TO-valueType, и оно предоставит оператор присваивания FROM-valueType-TO-wrappertype. Неявное преобразование-to-valuetype woudl выполняет команду read-from-map from from-given-key и не увеличивает счетчик te, а оператор = (from-valuetype, to-wrappertype) выполняет запись на карту.

Это наверняка работает, но такой подход может быть устаревшим. Я не владеет с изменениями от c'11, так что, возможно, некоторые лучше опция доступна сейчас - например, движение && семантика может изменить что-то здесь, то есть может быть перегрузка

valueType&& operator[](key) 

также возможно --- - но Я понятия не имею. Я знаю только подход return-a-transparent-wrapper.

EDIT: вот хороший (кажется, полный) Пример правильного оператора [] перегрузок, которые поддерживают чтение и запись, и что различает эти два:

stack: How to do some stuff with values assigned in subscript operator?

1

Если вы хотите, чтобы различать между чтением и операции записи, решение заключается в возврате прокси-объекта из operator [].

Для примера см https://stackoverflow.com/a/16132858/320726

2

Проблема не выводит, сама по себе; это то, что вы делаете, когда нет ключа . Я думаю, что очень важно, чтобы вы указали , прежде чем идти дальше. Есть много возможностей:

  • Вы можете делать то, что делает std::map, и вставить его со значением по умолчанию . Это очень удобно во многих случаях, но это означает , что вы не можете использовать [] на карте const.

  • Вы можете вернуть оператору указатель с указателем null , если объект отсутствует.Лично мне не нравится это для operator[]; это значит, что вам нужно писать вещи как: ValueType* p = myMap[ key ]; if (p != NULL) ..., что не кажется естественным для []. (С другой стороны, это делает работу хорошо с функцией find или get.)

  • Вы можете бросить исключение (или даже использовать утверждают, если вы обеспечить contains функцию, и иметь его в качестве предварительного условия от []).

  • Вы можете вернуть предопределенное значение по умолчанию. Это вид , противоположный первому решению; это означает, что operator[] никогда не изменит карту и что нет необходимости в неконстантной версии.

  • Наконец (и это, кажется, что вы стремитесь): вы можете иметь operator[] вернуть прокси, чтобы distiguish между myMap["a"], используемой в качестве RValue и myMap["a"] = something. Я чувствую, что это решение не выходит замуж за , так как работает C++, но он используется на других языках (например, как Python).

Для последнего решения, вы бы использовать что-то вроде:

class MyMap 
{ 
    class Proxy 
    { 
     MyMap* myOwner; 
     KeyType myKey; 
    public: 
     Proxy(MyMap* owner, KeyType key) 
      : myOwner(owner) 
      , myKey(key) 
     { 
     } 

     Proxy const& operator=(ValueType value) const 
     { 
      myOwner->insertOrUpdate(myKey, value); 
      return *this; 
     } 

     operator ValueType() const 
     { 
      if (!myOwner->contains(myKey)) { 
       throw UnknownKeyException(myKey); 
      } 
      return myOwner->get(myKey); 
     } 
    }; 

public: 
    Proxy operator[](KeyType key) 
    { 
     return Proxy(this, key); 
    } 
}; 
+1

Python более волшебный, чем это - среда выполнения Python превращает 'myMap [" a "] =" b "' в 'myMap .__ setitem __ ("a", "b") ', если существует' __setitem__'. Таким образом, вы не * обычно * нуждаетесь в прокси-объектах AFAIK. Я могу поверить, что их использование в Python существует, как и в C++, но обычное назначение элемента контейнера не является одним из них :-) –

+1

Кроме того, мне интересно, есть ли в C++ аргумент для объединения (1) и (3). То есть, 'const V & operator [] (const K &) const' выдает исключение, если ключ отсутствует, а неконстантный' operator [] 'возвращает неконстантную ссылку и вставляет запись, если ключ отсутствует. Обработка одной и той же ошибки двумя разными способами - это, как правило, плохая идея, но в этом случае она может соответствовать общему использованию и позволит использовать 'operator []' для const 'Mymap' для тех, кто хочет поймать на более высоком уровне. –

+0

@SteveJessop Да. Я говорил о стандартном Python 'map'; в дополнение к возможности переопределить '__setitem__' (путем получения« карты »), также существует' __missing__', который будет вызываться при чтении, если объект не найден. Важным моментом здесь является то, что Python отличает чтение и запись, а именно то, что нам нужно прокси для C++. –

Смежные вопросы