重载 C++ 中的下标 [] 运算符


序幕

最近,我决定在C++实施一棵红黑树作为个人项目。这已经存在并且实施起来很痛苦,几乎每行都发生段错误,但这既是红黑树(我在学校学习)的良好练习,也是C++(这总是很好的改进)。我让我的树处理 get、set、insert和 remove,世界一切都很好。但是,我缺少 C# 和 python 的简单语法,其中人们可以只索引地图,而不是使用笨拙的方法和点语法。在实践中,我们可以写点,这没什么大不了的,但这已经是一个实验,所以为什么不尝试让使用更容易(和更酷)呢?std::mapstd::setmap[key] = value

运算符重载

C++ 允许我们覆盖自定义类型的几乎所有运算符,例如 、、 和 订阅运算符 .C/C++ 中的正常行为是像 中一样自动执行指针算术和取消引用,但在语义上,它已成为索引(或下标,因此得名)数组、列表和映射的同义词。为类型重载此运算符的语法是使用签名创建方法。单数参数对应于方括号内的内容。此方法可以在地图上调用为+->=[]pointer[5] = *(pointer+5)<returnType> operator[](<paramType> <param>)mymap
<returnType> v = mymap[<param>];

树上的重载 []

像我们想要的那样实现订阅运算符有点困难,因为它需要提供两个功能,获取和设置。我们不能直接引用值字段,因为有特定的getter和setter,我们不希望它公开。因此,我们需要根据运算符的使用方式位置来改变行为。 应该调用 getter 方法,而应该调用 setter/insertion。确实没有办法使两个具有不同行为的重载(您可以自己尝试看看为什么),因此我们必须提出一个更棘手的解决方案。我们可以返回一个“代理”对象,该对象重载运算符并根据对其执行的操作调用正确的方法。int val = mymap[key];mymap[key] = val;operator[]

rbtree<K, V>::getSetProxy operator[](K key) {
    return getSetProxy(this, key);
}

现在调用变成了又变成了int val = mymap[key];int val = getSetProxy;mymap[key] = val;getSetProxy = val;

getSetProxy

此代理对象将根据用户尝试执行的操作处理获取和设置。代理的构造接受对树的引用,以便它可以执行操作,以及键,以便它知道在哪里获取/设置/插入。

设置的情况相当简单。我们将使用 assignment 运算符进行设置,因此我们可以重载它以调用 setter 方法。=

class getSetProxy {
    rbtree<K, V> *theTree;
    K key;
...
    void operator=(V value) {
        if (!theTree->setValue(key, value)) {
            theTree->insert(key, value);
        }
    }
...
}

赋值右侧的值在树中的键处设置或插入。

Get 有点棘手。C++中有一个运算符称为隐式强制转换运算符,签名 其中是要强制转换为的类型,只是表示此函数无法修改类。每当需要强制转换为其他类型时C++都会调用此函数。operator T() const;Tconst

myclass myobj = myobj();
int myint = myobj;
//          ^^^^^
//          implicit cast int() is called

所以在 中,将被调用。我们可以重载它以获得这样的功能:T val = getSetProxy;operator T()

class getSetProxy {
    rbtree<K, V> *theTree;
    K key;
...
    operator V() const {
        return theTree->getValue(key);
    }
...
}

将一切整合在一起

请原谅我滥用符号和平等以及所有即将发生的数学。

V value = mymap[key];

→→
V value = getSetProxy{key = key};V value = getSetProxy.operatorV();
V value = mymap.getValue(key);

mymap[key] = value;(为了简单起见,假设键不在地图中)

→→
getSetProxy{key = key} = value;getSetProxy{key = key}.operator=(value);
mymap->setValue(key, value)

结语

C++很有趣,因为您可以真正使语言成为您自己的语言。我能够采用笨拙的语法,并在几行(尽管有点棘手)代码中使其更熟悉。整个项目的代码,包括这个下标部分

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/292447.html

(0)
上一篇 2022年11月1日
下一篇 2022年11月1日

相关推荐

发表回复

登录后才能评论