【问题标题】:C++ operator []C++ 运算符 []
【发布时间】:2015-06-15 07:14:29
【问题描述】:

我正在尝试实现一次用于 Set 和一次用作 Get 的运算符 [],我需要区分这两种情况,如 get 的情况,如果返回,我需要抛出异常值等于-1;而在 Set 的情况下,我只是覆盖该值。 苹果[2] = X; y=苹果[2];

我不知道如何区分这两种模式,我的函数签名是:

   double& Security::operator[](QuarterType index){
    if(index<0 || index>MAX_QUATERS){
        throw ListExceptions::QuarterOutOfBound();
    }
    return evaluation[index].getValueAddress();
   }

【问题讨论】:

  • 对您问题的稀疏描述向我表明,您将从重新设计中受益。我认为开始这个问题的一个更好的方法是写一个set方法和一个get方法,然后询问如何将它们结合起来,以便你可以通过operator[]来完成。
  • 这看起来类似于更常见的请求,在尝试从集合中读取缺失值时抛出operator[ ],但仍允许插入新值。

标签: c++ c++11 operator-overloading


【解决方案1】:

与 Python 或 C# 等语言不同,C++ 不为其运算符提供获取和设置模式。因此,您必须编写 operator[] 以便它返回一个在您希望使用的任何上下文中执行正确操作的对象,这通常意味着引用。

注意我说的是通常;您还可以做其他事情,例如返回具有以下成员的类的实例:

struct proxy
{
    operator double() const;
    void operator=(double x);
};

如果此代理对象在预期为双精度的上下文中使用,它将调用隐式转换运算符,该运算符用于执行您的 get 操作。类似地,如果有人给代理对象赋值,它会调用赋值操作符,它被实现来做你的集合操作。

(请注意,代理可能需要引用您的 Security 对象)

不过,这种方法并非没有困难。由于您的返回值不是doubledouble&amp; 或类似类型,它可能会导致与重载决议混淆,尤其是与模板函数一起使用时,并在与auto 一起使用时会造成很多混淆。而且您的代理对象甚至不能在需要 double&amp; 的上下文中使用!

因此,这是最后的手段,当您被逼到角落并且必须通过假装与double 合作的operator[] 进行访问时。在诉诸于此之前,您确实应该寻求其他选择,例如:

  • 重新设计您的程序,以便索引Security 对象可以只返回对doubles 的引用,而不需要更复杂的获取和设置操作。 (例如,更改不变量,以免出现异常数据,或在其他地方进行错误处理)
  • 适应使用专用的获取和设置操作。甚至给它们起更复杂的名称,以反映这样一个事实,即它们正在做的事情比人们通常认为的索引集合更重要。
  • 重新设计 API,以便用户期望从 operator[] 获得具有各种重要行为的代理对象,而不是期望使用 operator[] 来读取/写入 double 对象。

【讨论】:

    【解决方案2】:

    C++ 不容易区分

    appple[2] = X; 
    y=apple[2];
    

    最常见的解决方案是返回一个代理对象:

    struct AppleProxy
    {
       Security & obj; 
       unsigned index;
    
       AppleProxy(Security &, unsigned) : ... {}
    
       operator double()   // your getter
       {
          return obj.GetAt(index);
       }
    
       operator=(double rhs)
       {
          obj.SetAt(index, rhs);
       }
    }
    
    AppleProxy operator[](unsigned index) { return AppleProxy(*this, index); }
    

    代理需要非常注意细节,我省略了const 正确性、生命周期管理、获取地址 (double &amp; x = apple[2]; x = 17;) 等。

    由于陷阱,我倾向于避免它们。

    【讨论】:

      【解决方案3】:

      我正在尝试实现一次用于 Set 和一次用于 Get 的运算符 []

      这是不可能的。您可以实现具有不同签名的运算符的多个版本(即具有 const 和非 const 版本),但它们不会被正确调用。

      相反,请考虑使用您需要的功能实现 set 和 get 函数。

      【讨论】:

        【解决方案4】:

        您可以从 [] 运算符返回一个代理对象,该对象具有目标类型的隐式转换 operator doubleoperator =。如果调用了对话运算符并且您的值为-1,则抛出,如果调用了赋值,则进行赋值。

        【讨论】:

          【解决方案5】:

          查看 cppreference.com 上的 operator overloading 文章。 数组下标运算符部分解释了您需要什么:

          用户定义的类,提供类似数组的访问,允许两者 读取和写入通常为operator[] 定义两个重载: const 和非 const 变体:

          struct T {
                    value_t& operator[](std::size_t idx)       { return mVector[idx]; };
              const value_t& operator[](std::size_t idx) const { return mVector[idx]; };
          };
          

          如果已知值类型是内置类型,则 const 变体应按值返回。

          (续)

          因此,您应该定义double Security::operator[](QuarterType index) const,而不是const double&amp; Security::operator[](QuarterType index) const

          【讨论】:

          • 我认为这被否决了,因为它不处理问题的主要部分之一:在获取的情况下,如果返回,我需要抛出异常值等于-1;而在 Set 的情况下,我只是覆盖值
          【解决方案6】:

          “获取”版本可以采用const 引用并标记为const

          const double&amp; Security::operator[](QuarterType index) const

          “Set”版本可以按照你目前的方式编写:

          double&amp; Security::operator[](QuarterType index)

          当您需要强制调用const 版本时,您可以将您的对象const_cast 转换为const 类型。 (但不要反过来:如果原始对象是 const,则丢弃 const-ness 的行为是未定义的。

          但我个人认为这是不必要的复杂。摆脱运算符重载并改为编写单独的getset 函数可能更实用。您可以QuarterType 类做一些事情:也许在其中注入一个特征系统,允许函数相应地处理特定的QuarterType 实例。但这可能并不比拥有不同名称的单独函数更好。

          (如果QuarterType 是一个大对象,则考虑传递const QuarterType&amp;。这将防止获取值副本。)

          【讨论】:

          • “获取”版本不是必然是常量版本。如果对象是非常量的,它也可以是非常量版本。
          • @Bathsheba:这不是复杂化,而是答案。
          • 试图挽回一些尊严。如果它仍然被判断为无用或出现更好的答案;我会去的。
          猜你喜欢
          • 2012-11-26
          • 2013-10-23
          • 2021-09-02
          • 2011-06-15
          • 1970-01-01
          • 2017-03-29
          • 2016-02-19
          • 1970-01-01
          相关资源
          最近更新 更多