代理下标运算符覆盖是否始终优于非代理下标运算符?

问题描述 投票:0回答:1

我看到了其他一些十年前编写的 QnAs,它们实现了单独的下标运算符重载以进行读写。

对于即:

参考1

class String{
public: 
    class Cref;

    Cref operator[] (int i);
    char operator[] (int i) const;
    ...
};

class String::Cref{
    friend class String;
public:
    operator char() { return s.read(i);}
    void operator=(char c){s.write(i,c);}
    ...
};

参考2

class X;

class Proxy {
    X*  object;
    Key key;
public:
    Proxy(X* object, Key key): object(object), key(key) {}
    operator V() const { return object->read(key); }
    void operator=(V const& v) { object->write(key, v); }
};

class X {
public:
    V     read(key) const;
    void  write(key, V const& v);
    Proxy operator[](Key key)       { return Proxy(this, key); }
    V     operator[](Key key) const { return this->read(key); }
};

参考3

class CountingProxy
{
public:
    CountingProxy<T>& operator=(const T& o)
    {
        cout << "Is writing\n";
        counter_++;
        ref_ = o;
        return *this;
    }

    operator T()
    {
        cout << "Is reading\n";
        return ref_;
    }
    ...
}

class Array
{
public:
    CountingProxy<T> operator[] (int index) {        
        return CountingProxy<T>(changes, data[index]);
    }

    T operator[] (int index) const {
        cout << "Is reading\n";
        return data[index];
    }
    ...
}

...所有 3 种情况都定义了不返回代理类(或结构)的下标运算符重载的

const
变体。

    Cref operator[] (int i);
    char operator[] (int i) const;  // <---

    Proxy operator[](Key key);
    V     operator[](Key key) const;  // <---
    CountingProxy<T> operator[] (int index);

    T operator[] (int index) const;  // <---

看着这些,我以为那些const重写是在不写的时候调用的。

但是,当使用我自己的实现来实现简单的

std::map
包装器时:

#include <iostream>
#include <map>
#include <string>

using namespace std;


struct Proxy {
    string& s;
    Proxy(string& s) : s(s) {}

    operator string &() const {
        cout << "calling string()  (read-only)" << endl;
        return s;
    }

    void operator= (const char* val) {
        cout << "calling =  (write-only)" << endl;
        s = val;
    }
};


// Method for cout support
ostream& operator<<(ostream& os, const Proxy& self)
{
    // In real case, this can be replaced to `os << self.s;`.
    // But to log string() on stdout, making explicit conversion.
    string converted_str = self;
    os << converted_str;
    return os;
}


struct SubscriptOverloadDemo {
    map<string, string> some_map;

    Proxy operator[] (const char* key) {
        cout << "calling []" << endl;
        return Proxy(some_map[key]);
    }

    const string& operator[] (const char* key) const {
        cout << "calling const []" << endl;
        return some_map.at(key);
    }
};


int main() {
    SubscriptOverloadDemo t;

    // Proxy
    t["a"] = "asdf";

    // const string&?
    const string& s = t["a"];
    cout << s << endl;

    // Proxy
    t["a"] = "qwer";
    cout << t["a"] << endl;

    return 0;
}

...从不调用

const string& operator[]
,并且始终调用代理。

calling []
calling =  (write-only)
calling []
calling string()  (read-only)
asdf
calling []
calling =  (write-only)
calling []
calling string()  (read-only)
qwer

编译器资源管理器中查看 MSVC 和 gcc 的程序集时,也不会编译覆盖。

最终我尝试自己创建 JSON 对象(出于某种原因),但这种行为让我感到困惑,这是我的实现的错误还是按预期工作。

c++ operator-overloading
1个回答
0
投票

不存在实施错误。而是你从来没有给过调用

const T&
操作符[]的机会。它将仅应用于 const
SubscriptOverloadDemo
对象。

例如,尝试:

const SubscriptOverloadDemo t2{{ {"a", "asdf"}}};
std::cout << t2["a"] << endl;  // It will print  "calling const []"
© www.soinside.com 2019 - 2024. All rights reserved.