【问题标题】:Overloading operator[] only for members of a specific class仅为特定类的成员重载 operator[]
【发布时间】:2022-01-07 21:28:35
【问题描述】:

编辑:MyClass 已重命名为 ReverseStringAccess 以消除歧义。

我有一个封装了vector<string> 的类。该类有一个重载的operator[],可用于读取和修改向量的内容。这是它的外观(最低限度):

class ReverseStringAccess {
    public:
        ReverseStringAccess() {}
        ReverseStringAccess(vector<string> _arr) arr(_arr) {}
        string& operator[](int index) {
            return arr[index];
        }
    private:
        vector<string> arr;
};

现在我需要能够修改向量中每个字符串的内容,而无需直接访问向量(即某种operator[][],它只适用于属于此类成员的向量)。问题是使用ReverseStringAccess[][] 将导致operator[] 在字符串上的默认行为。比如这个语句:

ReverseStringAccess[i][j]

将给出向量中第 ith 字符串的 jth 字符。但我希望它(例如)改为获取向量中 ith 字符串的 (length - j - 1)th 字符,其中 length 是第 ith 字符串的长度。

这可能吗?如果是,怎么做?

【问题讨论】:

  • “不直接访问向量就修改向量中每个字符串的内容”是什么意思?为什么您当前的代码无法修改字符串?使用 myclass[…][…] = x 应该完全符合您的要求,不是吗?
  • “问题是使用MyClass[][]会导致operator[]对字符串的默认行为。”为什么会出现这个问题?
  • 是的,但是如果我需要myClass[i][j] 来引用arr[i][arr[i].size() - j - 1],即如果我希望它从后面访问字符串呢?
  • @WaisKamal 这没什么意义,这应该完成什么?
  • 现场演示:godbolt.org/z/9xsGqrsan另一个类有什么问题?

标签: c++ operator-overloading


【解决方案1】:

如果您希望my_object[i][k] 不调用std::string::operator[],则不要从MyClass::operator[] 返回std::string&amp;,而是实现所需[] 的代理:

class MyClass {
    public:
        MyClass() {}
        MyClass(vector<string> _arr) arr(_arr) {}

        struct MyProxy {
             std::string& str;
             char& operator[](size_t index) { /.../ }
             const char& operator[](size_t index) const { /.../ }
        };

        MyProxy operator[](int index) {
            return {arr[index]};
        }
    private:
        vector<string> arr;
};

【讨论】:

  • 这里的问题是MyClass::operator[] 现在必须返回一个MyProxy,而它应该返回一个string
  • @WaisKamal 您可以轻松地将转换运算符添加到 std::string&amp; 到该 MyProxy 类。
  • 谢谢,我完全忽略了这一点 :')
【解决方案2】:

问题是如何通过[][]vector&lt;string&gt;的成员实现反向索引。

这可以通过 std::string 的包装类来实现:

template<typename T>
class reverse_access {
    T& ref;
public:
     // create wrapper given reference to T
     reverse_access(T& ref_)
         : ref(ref_)
     {}

     // reverse access operator []
     auto operator[](size_t i) -> decltype(ref[0])
     { return ref[ ref.size() - 1 - i]; }
     auto operator[](size_t i) const -> decltype(ref[0])
     { return ref[ ref.size() - 1 - i]; }

      // allow implicit conversion to std::string reference if needed
     operator T&() { return ref; }
     operator const T&() const { return ref; }
};

// inside MyClass:
        reverse_access<string> operator[](int index) {
            return reverse_access<string>(arr[index]);
        }
        reverse_access<const string> operator[](int index) const {
            return reverse_access<const string>(arr[index]);
        }

并在 MyClass 中的 operator[] 中使用 return reverse_access&lt;std::string&gt;(arr[index]);。 添加的转换运算符允许隐式转换为对原始类型的引用。

另一种选择是使用可以接受 2 个参数的不同运算符:myclass(vec_index,str_index):

        string::reference operator()(size_t vec_index, size_t str_index)
        {
            return arr[vec_index][ arr[vec_index].size() - str_index ];
        }
        string::const_reference operator()(size_t vec_index, size_t str_index) const
        {
            return arr[vec_index][ arr[vec_index].size() - str_index ];
        }

第三种解决方案是在构造 ReverseStringAccess 时反转所有字符串:

ReverseStringAccess(vector<string> _arr) arr(_arr) 
{
   for (auto& str : arr)
       std::reverse(str.begin(), str.end());
}

【讨论】:

  • 同样的问题:现在MyClass 必须返回reverse_access&lt;string&gt; 而不是string。顺便说一句,感谢您提供更合适的名称 :)
  • 即使它是reverse_access&lt;string&gt;,您仍然可以将它传递给任何采用std::string 的函数。但是,如果您真的希望 [] 返回 std::string&amp;,请使用其他解决方案,或者将所有字符串保持反向。
  • @WaisKamal:添加了第三个选项来反转类 ReverseStringAccess 的构造函数中的所有字符串。
  • 谢谢,我想我会选择第一个选项(第三个不切实际)。
猜你喜欢
  • 2019-06-09
  • 1970-01-01
  • 2011-07-19
  • 2012-01-18
  • 2012-04-06
  • 1970-01-01
  • 2010-12-22
  • 2012-05-03
  • 2019-02-24
相关资源
最近更新 更多