【问题标题】:distinguish between read and write using operator [] overloading in c++在 C++ 中使用运算符 [] 重载区分读取和写入
【发布时间】:2015-06-12 15:26:29
【问题描述】:

我有一个具有预测数组的安全类 - 预测是一个类,它只包含一个双精度数。 我想允许更改双精度值,但只允许正值, 并且在尝试读取双精度时,如果该值未初始化(在我的代码中等于-1),则抛出异常。 我在
中也有双重运算符 类似的东西:

class Prediction{
    double value;
public:
    .....
    Prediction::operator double() const {
        return this->prediction;
    }
    Prediction::operator=(const double value){
       ...
        //check value
    }

}

class Security{
   ...
    Prediction& Security::operator[](int index){
        return predArray[index];
    }
}

Prediction *predArray = new Prediction[4];
//default constructor set the value -1;

double a = predArray[0] //should throw an exception, because predArray[0] = -1
predArray[0] = 4; //should be O.K. because I want to change the value
predArray[1] = -4; //should throw exception, because trying to put negative value;

我在哪里定义阅读和写作,因为我在阅读和写作时做不同的事情。

谢谢

【问题讨论】:

    标签: c++ overloading operator-keyword


    【解决方案1】:

    你不能在operator[] 中这样做。操作员无法知道它返回的值将如何使用。因此,您必须将其作为返回对象的函数。您可以很容易地处理对负值的赋值,方法是将返回对象的赋值运算符放入其中。

    Prediction::operator=(const double value){
        if (value < 0)
            throw something;
        ...
    }
    

    如果你想抛出这个语句:

    double a = predArray[0];
    

    您必须在转换为双运算符时这样做。

    Prediction::operator double() const {
        if (value < 0)
            throw something;
        return value;
    }
    

    【讨论】:

      【解决方案2】:

      结合使用转换运算符和转换构造函数,您可以获得这种行为。此示例代码应该让您了解需要如何实现类:

      class Foo
      {
          int value;
      public:
          Foo() { value = -1; }
          Foo(int value) {
              if (value < 0) cout << "error\n"; else { cout << "ok\n";  this->value = value; }
          }
          operator int() { if (value < 0) cout << "error\n"; else return value; }
      };
      
      class Bar
      {
          Foo * fooArray;
      public:
          Bar() { fooArray = new Foo[4]; }
          Foo & operator [](int i) { return fooArray[i]; }
      };
      
      int main()
      {
          Bar test;
          int foobar = test[0];
          test[1] = 4;
          test[2] = -4;
          cin.get();
          return 0;
      }
      

      输出:

      error
      ok
      error
      

      【讨论】:

        【解决方案3】:

        中心思想如下:您可以返回一个带有重载operator= 的代理,而不是返回一个double&amp;(以及其他所有必需的)。然后,代理执行检查。

        struct reference_proxy
        {
            reference_proxy(double &_d) : d(_d) {}
            reference_proxy& operator=(double rhs)  //operator= throws when rhs<0
            {
                if(rhs<0.0)
                {
                    std::cout<<"throw exception"<<std::endl;
                }
                else
                {
                    std::cout<<"ok"<<std::endl;
                    d = rhs;
                }
                return *this;
            }
        
            operator double ()  //cast to double gives an error when uninitialized
            {
                if(d<0.0)
                {
                    std::cout<<"throw exception"<<std::endl;
                }
                return d;
            }
        
            // add further required functions like operator+= etc.
        private:
            double& d;
        };
        

        然后你可以在你的其他类中使用它:

        struct Prediction
        {
             operator double& () { return d; }
             double d = -1.0;
        };
        
        struct Security
        {
            template<typename ... Args>
            Security(Args&& ... args) : v(std::forward<Args>(args) ...) {}
        
             auto operator[](int i)
             {
                 return reference_proxy(v[i]);
             }
            std::vector<Prediction> v;
        };
        

        应用:

        int main()
        {
            Security s(10);   
        
            double a = s[0]; //prints "throw exception"
            s[0] = 4;        //prints "ok"
            s[1] = -4;       //prints "throw exception"
        
            return 0;
        }
        

        DEMO.

        请注意,此方案还可用于更复杂的操作。例如:通知观察者模式中的依赖类。

        【讨论】:

        • reference_proxy 应该实现operator double() 而不是operator double&amp;(),否则有人可以这样做并绕过安全保护:s[0] = 4; double &amp;d = s[0]; d = -4; // updates Prediction::d directly!
        • @RemyLebeau:感谢指正! ...我的胃里有这种不舒服的感觉:-)
        【解决方案4】:

        几点

        1. predArray 数组应该是 Security 的成员(示例代码中未显示)

        2. 通过 [] 运算符的索引访问应该在 Security 实例上,而不是在 predArray 上。变量 predArray 是对象的原始数组,而不是保存数组的对象。

        例如:

        Security o = new Security();
        double a = o[0] //should throw an exception, because predArray[0] = -1
        o[0] = 4; //should be O.K. because I want to change the value
        o[1] = -4; //should throw exception, because trying to put negative value;
        
        1. 在 return 语句前添加对 Prediction::operator double()Prediction::operator=(const double value) 的正值检查;

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-09-12
          • 2012-09-19
          • 2010-11-27
          • 1970-01-01
          • 2016-02-19
          • 1970-01-01
          相关资源
          最近更新 更多