【问题标题】:Overloaded operator isn't usable with the class it was defined for重载运算符不能用于为其定义的类
【发布时间】:2019-09-09 22:49:26
【问题描述】:

我已经重载了运算符“-”来获取一个类的两个对象并输出一个新对象,但是当我使用它时,例如。 obj3 = obj1 - obj2,我收到一条错误消息,提示没有运算符与这些操作数匹配。

vctmath.h 中命名空间的声明:

#ifndef VCTMATH
#define VCTMATH
namespace vctmath {
    Vect operator -(Vect a, Vect b);
}
#endif

主vctmath文件中的定义;

#include "Vect.h"
#include "vctmath.h"
Vect vctmath::operator -(Vect a, Vect b) {
    Vect output(0);
    output.SetX(a.GetX() - b.GetX());
    return output;
}

这是 Vect.h 文件中的类声明

#ifndef VECT
#define VECT

class Vect {
private:
    float x;
public:
    Vect(float);
    const float GetX(void);
    void SetX(float a);
};
#endif

这是Vect.cpp中Vect的定义:

#include "Vect.h"
#include "vctmath.h"

Vect::Vect(float a): x(a) {}
const float Vect::GetX(void) { return x; };
void Vect::SetX(float a) {
    x = a;
}

主函数创建 Vect 类的两个对象,然后尝试使用新重载的 - 运算符:

#include "Vect.h"
#include "vctmath.h"
int main() {
    Vect vect1(0);
    Vect vect2(1);
    Vect vect3 = vect1 - vect2; //this is where the problem is
    return 0;
}

错误是E0349;没有运算符“-”匹配这些操作数, 操作数类型是 Vect - Vect。

【问题讨论】:

  • @KaenbyouRin 哎呀:P
  • 那仍然不是minimal reproducible example。但它更接近。至少我们现在可以看到问题所在。
  • @LightnessRacesinOrbit 现在似乎是命名空间的问题。我的直觉是正确的。 :P
  • @KaenbyouRin 是的,对不起,哈哈。我不知道你可以限定这样的函数定义。

标签: c++ class operator-overloading


【解决方案1】:

Argument-dependent lookup 不会在随机命名空间中搜索全局命名空间中类型的运算符重载。

Vectvctmath 命名空间之间没有关系,因此编译器无法找到您要使用的重载。

您可以:

  • 在使用操作符之前打开命名空间:using namespace vctmath
  • Vect 移动到命名空间
  • 将操作符定义为成员方法,Vect::operator-

【讨论】:

  • 第二个要点是正常的解决方案。第三种选择很差。
  • @M.M:第三种解决方案在所有情况下都不差。这实际上取决于您的类型以及您将如何使用它。除非您需要使用基本类型重载操作,例如float + Vect,否则两者之间没有太大的实际区别
【解决方案2】:

不清楚你是如何定义 Vect 的。显然,在您显示的代码中,现在的问题在于名称空间内名称的可见性。建议您在使用命名空间中定义的类时显式使用命名空间名称。

我建议您更改 Vector.h(以及相应的 .cpp):

... 
namespace vctmath {
    class Vect {
    ...
    };       
} // namespace vctmath
....

main.cpp

int main() {
    vctmath::Vect vect1(0);
    vctmath::Vect vect2(1);
    Vect vect3 = vect1 - vect2;
    return 0;
}

如果由于某种原因您不想将 Vect 放入命名空间,您还有其他选择: a) 显式调用运算符:

Vect vect3 = vctmath::operator-(vect1, vect2);

b) 使用适配器设计模式:

Vect operator -(Vect& a, Vect& b) {
    return vctmath::operator-(a, b);
}

int main() {
    Vect vect1(0);
    Vect vect2(1);
    Vect vect3 = vect1 - vect2;
    return 0;
}

【讨论】:

  • 好吧,我的错误我不知道你可以用它的命名空间名称来限定一个函数定义!
  • 我建议将Vect 也放在命名空间中,以便 ADL 可以找到操作员。您想将此添加到您的答案中吗?
猜你喜欢
  • 2022-07-04
  • 2021-08-06
  • 1970-01-01
  • 2020-10-13
  • 2011-01-29
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多