简体   繁体   中英

Operator Overloading subscript and assignment operator for multiple tasks

I want to overload the operator [] and = for multiple tasks (in a dictionary class that I made).

when I write for example:

d["Home"] = 5;

and if there is no "Home" key, it will create a key and assign the value to 5 , and if there is the key, it will change its value to 5 .

and also, when writing

int i = d["Home"];

the operator will return the value of the "Home" key. I have tried to do that with 2 classes ( Dict and Node ) but I can't understand why the code doesn't compile and it's not working.


this is the Dict header:

#include <iostream>
#include <vector>
#include "Node.h"
using namespace std;


template <class K, class V>
class Dict {
protected:
    vector<K> keys;
    vector<Node<V>> values;
public:
    Dict();
    V& operator[](const K &str);
};

this is the Dict cpp:

#include "Dict.h"

template <class K, class V>
Dict<K,V>::Dict() {};

template <typename K, typename  V>
V& Dict<K,V>::operator[](const K &str) {
    V lol;
    for(int i = 0; i < this->keys.size(); i++){
        if(this->keys[i] == str){
            Node<V> n = this->values[i];
            return n.value;
        }
    }
    this->keys.push_back(str);
    return lol;
}
template class Dict<string, int>;

this is the Node header:

#include <iostream>
#include <vector>
using namespace std;


template <class V>
class Node {
protected:
    Node& operator=(const V& val);
public:
    V value;
};

this is the node cpp:

#include "Node.h"
template <typename  V>
Node<V>& Node<V>::operator=(const V &dict) {
    this->value = dict;
    return *this;

}

and this is the main:

int main() {
    Dict<string, int> d;

    d["Home"] = 6;
    cout << d["Home"] << endl;
    cout << "Home2" << endl;
    return 0;
}
return lol;

You return a reference to a temporary. lol gets destroyed at }

When str is not found, you also need to insert a default Node<V> in values.

template <typename K, typename  V>
V& Dict<K,V>::operator[](const K &str)
{
    for(int i = 0; i < this->keys.size(); i++)
    {
        if(this->keys[i] == str)
        {
            // Found, return corresponding value by reference.
            return this->values[i].value;
        }
    }
    // Not found, Insert into keys and values.
    this->keys.push_back(str);
    this->values.push_back(Node<V>()); //this will insert a default corresponding value in values.

    return this->values.back().value; //this will return reference to the recently added value node 
}

See code in action

I think you are overcomplicating things here a bit.

First of all, as Yksisarvinen has already mentioned in the comment above, you are defining a templated class in a translation unit which is only possible under certain circumstances. It's explained fairly well in the link Yksisarvinen has posted.

Second, as Gaurav has noticed, you are returning a temporary from a function and since you said that your code compiles, I suspect you are suppressing the compiler warnings, which isn't the best practice, as it leads to nasty bugs.

Anyway, to your question of creating a dictionary, you should be just fine with using only one storage container for the keys and values. Then, when you want to access the value using some key, you can go through the container and look if the key already exists, if it does, return the value, if not, insert the key with a default-constructed value and return it.

It can be as simple as this (Dict.h):

#include <vector>
#include <algorithm>
using namespace std;

template <class TKey, class TValue>
class Dict {
    struct KeyValue {
        TKey key;
        TValue value;
        KeyValue(TKey key, TValue value)
            : key(move(key))
            , value(move(value)) {}
    };

    vector<KeyValue> pairs;

public:
    Dict() = default;

    TValue& operator[](const TKey &key) {
        auto match = find_if(pairs.begin(), pairs.end(),
            [&key](const KeyValue& pair) { return pair.key == key; }
        );
        if (match != pairs.end()) {
            return match->value;
        }
        pairs.emplace_back(key, TValue());
        return pairs.back().value;
    }
};

LIVE DEMO


Another bad habit I can see in your code is not using namespace scope resolution operator, but rather polluting the global namespace with that using namespace std; statement. That can hit you pretty badly if you start using more libraries and generally working on bigger codebases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM