【问题标题】:How to overload C++ operator, but for only certain inputs?如何重载 C++ 运算符,但仅适用于某些输入?
【发布时间】:2021-08-03 05:13:35
【问题描述】:

我有一个类,我想为它重载加法运算符。对于我的用例,只有在每个对象的 a 变量相等的情况下才允许添加才有意义。

处理不适用的情况的最佳方法是什么?抛出异常,还有什么?

class A {
private:
    int a, b;

public:
    A(int a, int b)
        :a(a), b(b) {}

    A& operator+=(const A& rhs) {
        if (this->a == rhs.a) {
            this->b += rhs.b;
            return *this;
        }
        else { //this->a != rhs.a
            //what should I put here?
        }
    }
};

.

编辑:

这些对象是在文件 io 运行时创建的。

这些对象代表频谱中的一个数据点。仅当两个数据点位于同一位置时,将它们的强度相加才有意义。

a 仅限于范围(-180.0, 360.0)

【问题讨论】:

  • 在这种情况下抛出可能是有意义的,因为将正确的类型传递给运算符似乎是类用户的责任。
  • 抛出异常,或者改变用例。
  • a成为模板变量怎么样?然后可以在编译时检查它。此外,这个用例并不简单。为什么+= 只能在某些状态下工作?
  • 理想情况下,非法状态应该是不可代表的。在您的情况下,a 可能是模板参数而不是成员变量。
  • a 值是否有限制范围?

标签: c++ operator-overloading


【解决方案1】:

这闻起来像 a 是类型的属性,而不是值的属性...这个类到底代表什么?

解决此问题的最小可行(恕我直言)方法是明确地从“任何事情发生”类型转换为“与 a 的特定值兼容的类型”。即:

MyClass x(1,2), y(1,5);

x += y; // won't compile

x.makeCompatibleWith(y) += y; // will compile

拥有像+= throw 这样的算术运算符通常是一种悲观。相反,让其他东西假设成本 - 然后成本是明确的,您可以保留+= nothrow。也很容易在项目中搜索成本高昂的操作(好吧,makeCompatibleWith 并不是特别昂贵,只是比 += 贵,因为它增加了异常处理的开销)。

假设无效情况是要在测试中捕获的,makeCompatibleWith 函数可以assert 它需要的条件,但在发布版本中它会返回一些虚拟对象,将+= 变为 no- op,因为它不会修改 x - 同时仍然保持 += 非常简单和快速。

至于makeCompatibleWith 究竟应该返回什么:这取决于你。可以是携带引用的类型,例如:

class MyClass
{
  int a, b;
  struct Internal
  {
    MyClass &val;
    Internal(MyClass &val) : val(val) {}
    MyClass &operator+=(const MyClass &o) noexcept {
      val.b += o.b;
      return val;
    }
    MyClass operator+(const MyClass &o) const noexcept {
      return { val.a, val.b + o.b };
    }
  };
public:
  MyClass() : a{}, b{} {}
  MyClass(int a, int b) : a(a), b(b) {}
  Internal makeCompatibleWith(const MyClass &o) noexcept {
    thread_local static MyClass dummy;
    assert(a == o.a);
    if (a != o.a)
      return { dummy };
    return { *this };
  }
};

请注意,如果 dummy 不是线程本地的,则在多线程中使用 makeCompatibleWith 时将是未定义的行为。

【讨论】:

  • 这些对象代表光谱中的一个数据点。仅当两个数据点位于同一位置时,添加它们的强度才有意义。
  • “这通常是一种悲观主义……”我想我同意。我可以为这些写一个容器来处理平等问题,让用户处理容器,而不是单个元素......
  • 只有在两个数据点位于相同位置时,才将它们的强度相加才有意义。 然后,断言 + 测试覆盖率是恕我直言的方法。至少审计这样的使用很容易。
  • 另一种方法是不让用户直接添加数据点,让添加光谱的操作员完成这项工作。这样一来,平均值之类的东西就不会容易出错——而且,如果光谱以某种方式具有稍微不同的波长覆盖范围,则添加总是会提供一个联合。或者,专门的平均操作员可以向数据点添加一个属性,该属性将累积对给定点进行的平均次数。等等。但这是特定于应用程序的,很容易想出永远不会被使用的愚蠢场景 - 所以最好不要过度设计这些东西。
  • 是的。我认为容器将暴露给用户,并在后台使用各个数据点。我可以随意抛出异常,并处理它们以使容器成为 noexcept
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-28
  • 2018-09-10
  • 2013-12-15
  • 2012-12-30
  • 1970-01-01
  • 2015-10-20
  • 2017-09-09
相关资源
最近更新 更多