用于多个数组/向量的重载索引操作符

C++ Overload index operator for more than one array/vector

本文关键字:重载 索引 操作符 向量 数组 用于      更新时间:2023-10-16

我不是高级程序员。我如何重载[]操作符的类,有两个(或更多)数组/矢量类型变量?

class X
{
protected:
    std::vector<double> m_x, m_y;
public:
    double& operator[](const short &i) { return ???; }
};

我应该为???使用什么,或者我如何做到这一点(可能添加其他定义?)以便能够调用任何一个变量?
附加问题:这是否允许class derived : public X类型的其他类访问m_xm_y进行写入?


更新:

谢谢每个人的回答,但我担心如果我划清界限,那么我的第一个问题的答案是否定的,第二个问题的答案是肯定的。较长的版本意味着一个额外的struct,或class,或普通的setter/getter,我想通过使用一个简单的函数来避免这一切。
目前的解决方案是对每个类中的每个变量的(临时)引用,以避免额外的X::类型(并保持代码清晰),因为m_x将以某种方式存在。

您可以为此编写一个函数,如:

double &get(unsigned int whichVector, unsigned int index)
{
   return (whichVector == 0 ? m_x[index] : m_y[index]);
}

或使用operator():

    struct A
    {
        std::vector<int> a1;
        std::vector<int> a2;
        int operator()(int vec, int index)
        {
            return (vec == 0 ? a1[index] : a2[index]);
        }
    };
    A a;
    auto var = a(0, 1);

但是,这仍然有点奇怪:)也许你应该在外面给出一个const ref,比如:

const std::vector<double> &getX() const { return m_x; }

和第二个问题:protected在public继承中将被转换为private (child/derived可以访问这些成员)

假设您希望m_xm_y根据相同的参数和单个返回值进行索引:

struct XGetter
{
   double& x;
   double& y;
};
XGetter operator[](const short &i) { return { m_x[i], m_y[i] }; }

const过载:

struct XGetterReadOnly
{
   double x;
   double y;
};
XGetterReadOnly operator[](const short &i) const { return { m_x[i], m_y[i] }; }

编译器将在适当的地方优化掉中间类XGetterXGetterReadOnly,如果你是c++的新手,这可能很难让你明白。

如果使用mixin不让你感到不舒服,你可以使用这样的标签调度:

#include <utility>
#include <vector>
#include <iostream>
template <size_t I>
struct IndexedVector {
   std::vector<double> v;
   IndexedVector():v(10){}
};
template <size_t I>
struct tag {
   int i;
};
template <size_t S, class = std::make_index_sequence<S>>
struct MixinVector;
template <size_t S, size_t... Is>
struct MixinVector<S, std::index_sequence<Is...>>: IndexedVector<Is>... {
   template <size_t I>
   double &operator[](tag<I> i) {
       return IndexedVector<I>::v[i.i];
   }
};
int main() {
   MixinVector<2> mv;
   mv[tag<0>{0}] = 1.0;
   std::cout << mv[tag<0>{0}] << std::endl;
}

要使用std::index_sequence,你需要编译器支持c++14(你可以在c++11中实现它)。通过简单的MixinVector模板参数修改,该方法可以很容易地扩展到任意数量的向量。

无论是在概念层面还是在设计层面,都存在很多问题。

你能同时用手指指着两个不同的东西吗?没有?这就是为什么你不能用一个索引来处理两个不同的向量,以保持它们的区别。

你可以做很多事情:任何将两个值"组合"成一个值的方法都是好的从语法的角度来看:

return m_x[i]+m_y[x]return sin(m_x[i])*cos(m_y[i])return whatever_complicated_expression_you_like_much

但这是什么意思?问题是为什么在你的课堂上有两个向量?你想让他们代表什么?(语义上)索引它们是什么意思?

我可以做的是保持它们的区别

auto operator[](int i) const 
{ return std::make_pair(m_x[i],m_y[i]); }

得到一个std::pair<double,double>,它的fistsecond成员分别是m_x[i]和m_y[i]。

还是……你可以return std::vector<double>{m_x[i],m_y[i]};


关于你的另一个问题:是的,继承为public使新类能够访问受保护的部分:这就是protected的作用。

是的,你可以R/W: public,protected和private是关于可见性的,而不是可读性和可写性。这就是const的作用

但是:你的类代表什么?没有这些信息,我们就不能确定什么有意义,什么没有意义。


好的,说明你的评论:

需要两个不同的函数:一个用于读(double operator[](unsigned) const),一个用于写(double& operator[](unsigned) const)

如果你知道向量有一个已知的长度,比如200,你可以编写一个像i/1000这样的索引转换来识别向量,i%1000来获得索引,所以0..199是第一个,1000…2000年第二次……地址是第三……等。

还是……您可以使用std::pair<unsigned,unsigend>作为索引(like operator[](const std::pair<unsigned,unsigned>& i)),使用i.first来识别向量,i.second来索引它,然后调用x[{1,10}], x[{3,30}]等。

还是……你可以用

把向量链在一起
if(i<m_x.size()) return m_x[i]; i-=m_x:size();
if(i<m_y.size()) return m_y[i]; i-=m_y:size();
if(i<m_z.size()) return m_z[i]; i-=m_z:size();
...

以便连续索引它们。

但是你可以使用向量数组而不是不同的向量变量得到更多的算法解

如果你有std::array<std::vector<double>,N> m;而不是m_x, m_y和m_z,上面的代码可以…

for(auto& v: m)
{
   if(i<v.size()) return v[i];
   i-=v.size();
}

可以返回有两个double的struct

struct A{
 double& x;
 double& y;
 A(A& r) : x(r.x), y(r.y){}
 A(double& x, double& y) : x(x), y(y){}
};

class X
{
protected:
    std::vector<double> m_x, m_y;
public:
    A operator[](const short &i) { 
      A result(m_x[i], m_y[i]);
      return result;
    }
};

感谢编辑@marcinj