C ++重载()运算符,左值和右值

时间:2019-05-19 10:37:52

标签: c++ arrays operator-overloading

考虑以下简单的类。

#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的内容。应该可以只为 any 元素分配一个值,但是不可能查询以前从未设置过的元素的值。我以为可以使用()的不同版本,其中一个const就足够了,但是显然,编译器始终使用运算符的较高版本,而从未使用较低版本。我该如何解决这个问题?

我阅读了有关代理对象(例如here)的信息,但是我认为这种实现在我的情况下将无法正常工作,因为我正在使用数组。所以 a)没有代理人是否有可能,如果没有 b)在我的情况下,代理应该是什么样子?

1 个答案:

答案 0 :(得分:0)

所以这是我终于想出的解决方案:

#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