0

有人可以用初学者的方式解释运算符重载的工作原理吗?我需要将“+”运算符作为成员函数重载,并链接到对象数组。我从谷歌读过一些东西,它的运行方式似乎与“+”相同,没有超载,所以我真的很困惑。

这是我到目前为止的声明:

ALIST<t_type> & operator+(const t_type );

所以我在公共部分的 ALIST 类中声明了这一点。“+”运算符现在是否已重载,还是在此函数定义中我需要做更多才能使其重载?

另外,一旦它最终超载,我现在可以用它做什么?超载它有什么意义?

请用初学者的术语解释一下,谢谢。

4

5 回答 5

3

这是为什么的一个例子。

假设您正在实现一类特殊向量。比如一个Color类。 Colors 将基本上是具有 4 个值的向量,r,g,b,a。

现在我们正在编写一个图形引擎,在我们的程序中,我们经常想知道当来自两个不同来源的光作用于我们正在评估的像素(如光线追踪器中)时,像素会发生什么。定义一个 + 运算符来评估当来自两个不同光源的光加在一起时会发生什么会很方便。

如果我们没有运算符,您可以在代码中编写将两个Colors 相加:

Color newColor = Color(
    color1.r + color2.r, 
    color1.g + color2.g,
    color1.b + color2.b,
    color1.a + color2.a
);

更糟糕的是,如果您与光的物理特性密切合作,您可能会发现颜色无法正常添加。例如,它们可能会根据一些线性函数相加,例如 f(a) = a^2 ...(我不认为光不会这样做,它只是一个随机示例)。

f(a) = a^2; f(b) = b^2
f(a + b) = ??
a = f(a)^.5; b = f(b)^.5
a + b = f(a)^.5 + f(b)^.5
f(a + b) = (f(a)^.5 + f(b)^.5)^2 *yada yada yada i'm terrible at math.

这意味着我们Color现在添加的代码变成了

Color newColor = Color(
    pow(pow(color1.r, .5) + pow(color2.r, .5),2), 
    pow(pow(color1.g, .5) + pow(color2.g, .5),2),
    pow(pow(color1.b, .5) + pow(color2.b, .5),2),
    pow(pow(color1.a, .5) + pow(color2.a, .5),2), 
);

写出来很痛苦。但是,当然,如果我们使用Color类,并覆盖 add 运算符来为我们完成所有这些操作,我们可以在我们的代码中编写

Color color = color1 + color2;

Color类定义中定义了这个

Color Color::operator+(const Color &rhs) const {
     return Color(
           pow(pow(this.r, .5) + pow(rhs.r, .5),2), 
           pow(pow(this.g, .5) + pow(rhs.g, .5),2),
           pow(pow(this.b, .5) + pow(rhs.b, .5),2),
           pow(pow(this.a, .5) + pow(rhs.a, .5),2)
     ); 
}

由于我们的特殊添加代码只在一个地方,您可以更好地优化它,并且您程序其余部分的代码变得更具可读性。

至少这是一种看待它的方式。过去,我更喜欢这样的函数,addLights(color1, color2)因为它更容易编码,同样容易阅读,而且更易读,因为很明显它不是传统的vector添加。我敢打赌,你的整个职业生涯都不会凌驾于运营商之上,我认为你不会错过太多。

于 2012-05-22T20:02:42.107 回答
0

如果您有一个自定义类并且希望能够将该类的两个实例“添加”在一起,则 operator+ 重载将允许您自定义如何将两个对象“添加”在一起。

您现在需要在 .h 或 .cpp 文件中实现 operator+ 方法。

于 2012-05-22T19:19:47.160 回答
0

到目前为止,您得到了正确的声明,然后您需要实现它,例如,通过将输入参数添加到内部管理的数组来填充主体。

当您将其放在适当位置时,您将可以说 mylist = mylist + mytype;而不是mylist.add(mytype) 例如。在这种情况下没什么大不了的,但是如果您正在开发自然应该使用标准运算符(如数学矩阵、向量、复数等)的类,或者如果您[]在类中覆盖运算符,ALIST则更有意义。

于 2012-05-22T19:39:20.960 回答
0

默认情况下,运算符符号设计为与内置类型(int、char、string 等)一起使用。

C++ 的创建者不可能定义操作数应该如何为用户定义的类型工作,因此他实现了一个系统,您可以在其中重载它们并以在该对象的上下文中有意义的方式自己定义行为。

您通常会像这样重载运算符:

在类.h

class MyClass {
    int a;
    MyClass(int value) : a(value) {}
    MyClass MyClass::operator+(const MyClass&) const;
}

在类.cpp

MyClass MyClass::operator+(const MyClass& other) const
{
    return MyClass(this->a+other.a);
}

这将返回一个MyClass带有变量 a 的新变量,该变量设置为两个MyClassa 相加的值。完成后,您可以执行以下操作:

MyClass first(2);
MyClass second(5);
MyClass last = first + second;
std::cout << last.a << std::endl; // prints 7, which is the result of 2+5

如果不重载operator+on MyClass,将两个MyClass' 加在一起将是无效的。

于 2012-05-22T19:54:42.123 回答
0

如前所述,必须有一个实现。仅仅对重载进行原型设计并不能让编译器为您编写操作。

如果您是初学者(或至少,在“初学者术语”中寻求答案),运算符重载不一定是直接在重要项目中使用的最佳主意。涉及一些语义问题......因为这+是一个非常抽象的符号,对于阅读您的代码的人可能意味着许多不同的东西,而更具描述性的名称可能会更好。

请注意,即使是标准库也不提供诸如附加+=到向量之类的功能,因为它们存储可能添加在一起的元素...或附加向量...或在末尾添加一个元素...添加恶心[双关语意图]。将“添加”的一个定义称为最“正确”是很棘手的:

为什么不为 std::vector 重载 operator+=()?

(请注意,由于std::string不存储任意数学类型,所以它不那么模棱两可。)

也很难搜索这些运算符方法被调用的位置,因为您的方法没有唯一的名称可供搜索。要找到调用,您必须筛选+用于算术和字符串类等的上下文。

除了命名问题之外,我还会提到运算符重载在您以后是否要传递其他参数方面会束缚您的手。如果您想在每次将某些内容放入列表时使用优先级参数进行扩展怎么办?有一些技巧可以绕过它,例如将重载维护为默认实现以及使用参数化方法。或者您可以执行 iostreams 所采用的方法<iomanip>

http://www.cplusplus.com/reference/iostream/manipulators/

但这只是指出了在深入研究域中的运算符重载之前应该谨慎使用的想法。另一个需要注意的微妙之处是使用类的全局“朋友”函数重载与使用成员重载之间的区别。这里有一个讨论...

运算符重载:成员函数与非成员函数?

重要的一点是,如果您想为操作左侧出现非类(例如整数)的情况赋予意义,则无法将方法添加到int. 因此,您必须使其成为全局过载。

于 2012-05-22T20:01:41.467 回答