【问题标题】:Operator overloading [] and =运算符重载 [] 和 =
【发布时间】:2016-04-04 00:37:55
【问题描述】:

我正在尝试构建一个模板类,它是 C# 字典类的简化版本,称为“Map”。我遇到的问题是 [] 运算符重载和 = 运算符重载。

[] 运算符重载应该以允许像 mapObject[“keyString”]=value; 这样的语句的方式重载。在这种情况下,如果密钥不存在,则必须抛出异常。 重载的 = 运算符应该执行深层复制。

我做错了什么?

    #pragma once
#include <iostream>
#include <ostream>

using namespace std;

template<class K, class V>
class Map;

template <class K, class V>
class Entry;

//template<class K, class V>
//Map<K, V>& operator[](K* sKey);

template<class K, class V>
ostream& operator<< <>(ostream& os, const Map<K, V>& L);

template <class K, class V>
class Map
{
protected:
    Entry<K, V>     **ledger;
    Entry<K, V>     **temp;
    int             numOfEntries;

public:
    V               *valArray;

    Map();
    Map(const Map<K, V>& mapObject);
    ~Map();

    void ledgerAllocation();
    void tempAllocation();
    void entrySizePlus();
    void ledgerCopy();
    void tempCopy();
    void AddEntry(K key, V value);

    Map<K, V>& operator[](K* sKey);
    friend ostream& operator<< <>(ostream& os, const Map& L);
    Map<K, V>& operator=(const Map<K, V>& toBeCopied);
};


//Default constructor, might change at a later stage...
template<class K, class V>
Map<K, V>::Map()
{
    numOfEntries = 1;
}

template<class K, class V>
inline Map<K, V>::Map(const Map<K, V>& mapObject)
{
    ledger = new Entry<K, V>*;
    numOfEntries = 1;
    ledger = mapObject.ledger
}

//Default destructor, will need to change it later to properly delete an allocated array.
template<class K, class V>
Map<K, V>::~Map()
{
}

template<class K, class V>
inline void Map<K, V>::ledgerAllocation()
{
    ledger = new Entry<K, V>*[numOfEntries];

    for (int i = 0; i < numOfEntries; i++)
    {
        ledger[i] = new Entry<K, V>;
    }
}

template<class K, class V>
inline void Map<K, V>::tempAllocation()
{
    temp = new Entry<K, V>*[numOfEntries];

    for (int i = 0; i < numOfEntries; i++)
    {
        temp[i] = new Entry<K, V>;
    }
}

template<class K, class V>
inline void Map<K, V>::entrySizePlus()
{
    tempAllocation();
    ledgerCopy();

    ledgerAllocation();
    tempCopy();
}

template<class K, class V>
inline void Map<K, V>::ledgerCopy()
{
    tempAllocation();
    K cKey;
    V cValue;

    for (int i = 0; i < numOfEntries - 1; i++)
    {
        cKey = ledger[i]->getKey();
        cValue = ledger[i]->getValue();
        temp[i]->setKeyandValue(cKey, cValue);
    }
}

template<class K, class V>
inline void Map<K, V>::tempCopy()
{
    ledgerAllocation();
    K cKey;
    V cValue;

    for (int i = 0; i < numOfEntries - 1; i++)
    {
        cKey = temp[i]->getKey();
        cValue = temp[i]->getValue();
        ledger[i]->setKeyandValue(cKey, cValue);
    }
}

//Function that will add a new Key and Value to a new map-object within the array.
template<class K, class V>
void Map<K, V>::AddEntry(K newKey, V newValue)
{

    if (numOfEntries <= 1)
    {
        ledgerAllocation();
    }
    else
    {
        entrySizePlus();
    }

    this->ledger[numOfEntries - 1]->setKeyandValue(newKey, newValue);
    numOfEntries++;
}


template<class K, class V>
Map<K, V>& Map<K, V>::operator[](K * sKey)
{
    K Akey;
    V Avalue;

    for (int i = 0; i < numOfEntries; i++)
    {
        Akey = ledger[i]->getKey();
        Avalue = ledger[i]->getValue();

        if (Akey == *sKey)
        {
            return Avalue;
        }
        else
        {
            throw string("Key does not exist");
        }
    }
}

template<class K, class V>
Map<K, V>& Map<K, V>::operator=(const Map<K, V>& toBeCopied)
{
    if (ledger == toBeCopied)
    {
        return *this;
    }
    ledger = toBeCopied.ledger;

    return *this;
}

//Overloads the "<<" so that the command: cout << mapObject << endl; can be used to print the entire map.
template<class K, class V>
ostream & operator<< <>(ostream& os, const Map<K, V>& L)
{
    K pKey;
    V pValue;

    for (int i = 0; i < L.numOfEntries - 1; i++)
    {
        pKey = L.ledger[i]->getKey();
        pValue = L.ledger[i]->getValue();
        os << "[" << pKey << " , " << pValue << "]";
        if (i < L.numOfEntries - 2)
        {
            cout << " , ";
        }
    }
    return os;
}


template <class K, class V>
class Entry
{
protected:
    K key;
    V value;

public:
    Entry();
    ~Entry();

    void setKeyandValue(K skey, V sValue);
    K getKey();
    V getValue();
    void printKeyandValue();

};


template<class K, class V>
Entry<K, V>::Entry()
{
    this->key = NULL;
    this->value = NULL;
}

template<class K, class V>
Entry<K, V>::~Entry()
{
}

template<class K, class V>
inline void Entry<K, V>::setKeyandValue(K skey, V sValue)
{
    key = skey;
    value = sValue;
}

template<class K, class V>
inline K Entry<K, V>::getKey()
{
    return this->key;
}

template<class K, class V>
inline V Entry<K, V>::getValue()
{
    return this->value;
}

template<class K, class V>
void Entry<K, V>::printKeyandValue()
{
    cout << this->key << ": " << this->value << endl;
}

【问题讨论】:

  • 你知道std::map,是吗?
  • 是的,ofc,但我正在尝试做我自己的版本。
  • 好的,当然。然后我建议将代码归结为实际问题。
  • 可能对您有用/有趣:What is the copy-and-swap idiom.

标签: c++ operator-overloading


【解决方案1】:
    Akey = ledger[i]->getKey();
    Avalue = ledger[i]->getValue();

    if (Akey == *sKey)
    {
        return Avalue;

    // ...

你在这里做错了,当这个函数返回时,你返回了一个超出范围的对象的引用。一旦这个函数返回,这个引用就不再有效。

    Avalue = ledger[i]->getValue();

在这里,您调用getValue(),并将此方法调用的结果放入一个对象中,该对象是在此函数中声明的“本地”对象。

    return Avalue;

这会返回对该对象的引用。但是因为 this 是这个函数的一个本地对象,所以一旦这个对象被返回,这个对象就不再存在了。

您的一般做法是正确的,您的operator[] 需要返回一个引用。

但是,您需要返回对容器中原始值的引用,而不是“本地”对象,这是在 operator[] 方法中创建的临时对象,并在此方法返回时被销毁。

【讨论】:

  • 所以我仍然可以使用 Akey= ledger[i]->getKey();比较密钥?
  • 比较键与正确返回值无关。
  • 所以我可以删除V值; Avalue = 账本[i]->getValue();返回值;并将其替换为 return ledger[i].value; ?
  • 当我测试我的运算符重载时,我得到一个错误“没有运算符“[]”与这些操作数匹配。而 C2679“二进制 '[':没有找到采用右手操作数类型的运算符'int'(或没有可接受的转换)。这是为什么呢?
  • 好吧,因为它当然有问题。你应该修改这个问题,或者发布一个新的minimal reproducible example
【解决方案2】:

重载的 = 运算符应该执行深层复制。

Map&lt;K, V&gt;&amp; Map&lt;K, V&gt;::operator=(const Map&lt;K, V&gt;&amp; toBeCopied) 行:ledger = toBeCopied.ledger; 不执行深拷贝。两个对象都指向同一个账本。

【讨论】:

    猜你喜欢
    • 2016-02-19
    • 2012-11-26
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多