0

我班上有 2 个操作员有一点问题。

我的班级被宣布:

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"是 akeyType而不是MyMap类型。

我能怎么做 ?

4

5 回答 5

2

问题本身不在于输出;这是您在钥匙不存在时所做的事情。我认为您在更进一步之前指定非常重要。有很多可能性:

  • 您可以执行该std::map操作,并使用默认值插入它。这在许多情况下非常方便,但这确实意味着您不能[]在 const 映射上使用。

  • 您可以让运算符返回一个指针,如果对象不存在,则返回一个空指针。就个人而言,我不喜欢这个operator[];这意味着您必须编写类似的内容:ValueType* p = myMap[ key ]; if ( p != NULL ) ...,这对于[]. (另一方面,它确实适用于findorget函数。)

  • 您可以抛出异常(或者甚至使用断言,如果您提供一个contains函数,并将其作为 的前提条件 [])。

  • 您可以返回预定义的默认值。这与第一个解决方案有点相反;这意味着operator[] 永远不会更改地图,并且不需要非常量版本。

  • 最后(这似乎是您的目标):您可以operator[]返回一个代理,以便区分myMap["a"]用作右值和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 );
    }
};
于 2013-04-22T08:48:16.067 回答
1

当你写:

auto blah = map[key];

operator[] 用 a 调用key,它返回一个值。

当你写:

map[key] = blah;

然后 operator[key] 用 a 调用key,它返回一个值,然后 operator= 用blah参数调用该值。

这意味着可能很难检测到您实际在哪里读取或写入地图。

但是,通常,在 READ 案例中,案例可能会退回到被value const& operator[] const调用,而在写入期间,它会value& operator[] 没有 const标记。因此,您可能会尝试通过 const 说明符重载运算符:提供 2 个 operator[],一个 const,一个非常量,并且仅在后者中增加大小。

这很简单,但并不总是能正常工作,因为您有时可能会意外调用“operator[] as read”,但没有编译器可确定的 const 约束。我目前无法确切说明何时、如何以及是否有可能,但我想如果你对 constness 不太小心的话,你可以很容易地做到这一点。

如果你做到了,那么我知道的唯一选择是在非常量模式下为返回值提供一个包装器,并在 const 模式下保持正常:

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

您的包装器会记住您的 Map 的 ref& 并会记住 KEY,并且该包装器将提供隐式转换到 valueType,并且它将提供赋值运算符 FROM-valueType-TO-wrappertype。隐式转换为值类型将执行从映射到给定键的读取,并且不会增加计数器,而运算符=(从值类型,到包装类型)将执行对映射的写入。

这肯定会奏效,但这种方法可能已经过时了。我不熟悉 c'11 的更改,所以现在可能有一些更好的选项可用 - 例如,移动&& 语义可能会在这里改变一些东西,即可能是重载

 valueType&& operator[](key)

也有可能----但我不知道。我只知道 return-a-transparent-wrapper 方法。

编辑:这是一个很好的(似乎完整的)示例,它支持读取和写入并区分这两者:

堆栈:如何使用下标运算符中分配的值做一些事情?

于 2013-04-22T08:36:53.970 回答
1

如果要区分读取和写入操作,解决方案是从operator [].

有关示例,请参见https://stackoverflow.com/a/16132858/320726

于 2013-04-22T08:37:13.033 回答
1

“但是在我的 operator[] 中,我增加了 size 参数”。

不。检查密钥是否存在,并且size仅在插入新密钥时才增加。当您执行 astd::cout时,大概您仅在现有的键/值对上执行此操作。

[编辑] 鉴于评论,这是一个替代解决方案。在operator[]中,返回一个MyMap<KeyType, ValueType>::proxy。这包装了一个MyMap&Key。重载MyMap::proxy::operator=(ValueType)以分配新值,并递增size. 重载MyMap::proxy::operator ValueType() const以获取值。ValueType()如果密钥不存在则返回。

于 2013-04-22T08:24:39.903 回答
0

size只在key不存在时增加你的keys,对吧?就是std::map这样。因此,如果您只是打印地图的内容,您将读取现有键的值,因此size不会增加。

于 2013-04-22T08:23:36.720 回答