C 过载()运算符,LVALUE和RVALUE

C++ overload () operator, lvalue and rvalue

本文关键字:LVALUE RVALUE 运算符 过载      更新时间:2023-10-16

考虑以下简单类。

#include <iostream>
using namespace std;
class test
{
public:
  int* myvar;
  int sz;
  test()
  {
    sz = 10;
    myvar = new int[10];
  }
  void dump()
  {
    for(int i = 0; i < sz; i++)
    {
      cout << myvar[i] << " ";
    }
    cout << endl;
  }
  int& operator()(int index)
  {
    if(index >= sz)
    {
      int* newvar = new int[index+1];
      for(int i = 0; i < sz; i++)
      {
        newvar[i] = myvar[i];
      }
      sz = index+1;
      delete myvar;
      myvar = newvar;
    }
    return myvar[index];
  }
  const int operator()(int index) const
  {
    if(index >= sz)
    {
      throw "index exceeds dimension";
    }
    else
    {
      return myvar[index];
    }
  }
};

它应该像动态数组一样行为。我超载了((操作员。我的想法是,对于分配(lvalue(,将调用((的上部版本,而对于"仅读取"操作(rvalue(,则使用了((的下部版本。示例代码应该更清楚地解释我的意思:

int main()
{
  test x;
  // will give 10 times zero
  x.dump();
  // assign some values
  x(1) = 7;
  x(9) = 99;
  // will give
  // 0 7 0 0 0 0 0 0 0 99
  x.dump();
  // should give 7
  cout << x(1) << endl;
  // should give 99
  cout << x(9) << endl;
  // this will increase the size of myvar to 15 elements and assign a value
  x(15) = 15;
  // this should give
  // 0 7 0 0 0 0 0 0 0 99 0 0 0 0 0 15
  x.dump();
  // this should throw an exception because x(20) got never assigned a value!
  // but instead of calling the lower version of operator() it also calls the
  // upper, resulting in x being expanded now to 21 elements.
  cout << x(20) << endl;
  // will give 21 elements, instead of 16.
  x.dump();
  return 0;
}

因此,我通过((运算符访问myvar的内容。应该可以将值分配给元素,但是不可能查询以前从未设置过的元素的值。我认为,通过使用不同版本的((,其中一个为const就足够了,但是显然,编译器始终使用我的操作员的上部版本,而从来都不是下部版本。我该如何解决此问题?

我阅读了有关代理对象的信息,例如,我认为此实现在我的情况下不起作用,因为我使用了数组。所以a(如果没有代理?b(在我的情况下,代理人应该如何?

,所以这是我最终提出的解决方案:

#include <iostream>
using namespace std;
template <class T> class myclass
{
private:
  unsigned numel;
  T* elem;
public:
  class proxy
  {
    private:
        T*& elem;
        unsigned& numel;
        const unsigned index;
        proxy(T*& elem, unsigned& numel, unsigned index) : elem(elem), numel(numel), index(index) { }
        // didn't really need those two
        // proxy(const proxy&) = default;
        // proxy(proxy&&) = default;
        friend class myclass;
    public:
        proxy& operator=(const T& value)
        {
          if(index >= numel)
          {
            cout << "assignment to an element outside the range!" << endl;
            cout << "old size: " << numel << endl;
            cout << "new size: " << index+1 << endl << endl;
            T* newelem = new T[index+1];
            for(unsigned i = 0; i <= index; i++)
            {
              if(i < this->numel)
              {
                newelem[i] = this->elem[i];
              }
              else
              {
                newelem[i] = 0;
              }
            }
            if(this->elem != nullptr)
            {
              delete this->elem;
            }
            this->elem = newelem;
            this->numel = index+1;
          }
          this->elem[index] = value;
          return *this;
        }
        proxy& operator=(const proxy &other)
        {
          *this = (const T&)other;
          return *this;
        }
        operator T&()
        {
          if(index >= numel)
          {
            cout << "cannot query the value of elements outside the range!" << endl;
            cout << "# of elements: " << numel << endl;
            cout << "index requested: " << index << endl << endl;
            throw out_of_range("");
          }
          return elem[index];
        }
        operator const T&() const
        {
          if(index >= numel)
          {
            throw out_of_range("");
          }
          return elem[index];
        }
    };
  myclass() : numel(0), elem(nullptr) {};
  myclass(unsigned count)
  {
    this->numel = count;
    this->elem = new T[count];
  }
  ~myclass()
  {
    if(this->elem != nullptr)
    {
      delete this->elem;
    }
  }

  friend ostream& operator<<(ostream& os, const myclass& mc)
  {
    os << endl;
    for(unsigned i = 0; i < mc.numel; i++)
    {
      os << mc.elem[i] << "  ";
      os << endl;
    }
    os << endl;
    return os;
  }
  proxy operator()(unsigned index)
  {
    return proxy(this->elem, this->numel, index);
  }
};

int main()
{
  myclass<double> my;
  my(1) = 77;
  my(0) = 200;
  my(8) = 12;
  cout << my;
  try
  {
    cout << my(0) << endl;
    cout << my(1) << endl;
    cout << my(8) << endl;
    cout << my(10) << endl;
  }
  catch(...)
  {
    cout << "error catched" << endl << endl;
  }
  my(10) = 10101;
  cout << my(10) << endl;
}

终端上的输出看起来像:

assignment to an element outside the range!
old size: 0
new size: 2
assignment to an element outside the range!
old size: 2
new size: 9

200  
77  
0  
0  
0  
0  
0  
0  
12  
200
77
12
cannot query the value of elements outside the range!
# of elements: 9
index requested: 10
error catched
assignment to an element outside the range!
old size: 9
new size: 11
10101