通过引用传递-运算符重载

Passing by reference - operator overloading

本文关键字:运算符 重载 引用      更新时间:2023-10-16

在什么情况下,我们在运算符重载中通过引用传递对象?为什么?此外,运算符重载在哪些情况下有用(具体情况)?

编辑:语言:C++

您通过引用传递参数,要么是因为您想修改它们(这可能是您不想对运算符进行的,请参阅下文),要么只是因为传递简单指针比复制整个对象更有效。

至于"为什么超负荷",这主要是一个偏好问题。有一些经典的例子,比如有一个向量类,它可以让你添加向量或类似的东西——基本上,这些都是很好的例子,因为它们对一些新类应用了算术运算符所具有的相同的含义:无论你添加整数还是向量,在这两种情况下都写"x+y"是一种自然的表示法。这也是使用常量引用的经典原因——如果你写"a=b+c",你不希望b或c被修改,而且如果你所做的结果是读者所期望的,那么只重载运算符绝对是一种好的做法。

像智能指针(或迭代器,或其他"假装"为指针的东西)这样的东西喜欢重载运算符,如->或*(解引用运算符,而不是乘法)。同样的原因是,这些对象假装是指针,它们应该像指针一样使用,所以运算符重载被用来使它们看起来更像指针。

我还重载了","运算符,将参数输入到字符串格式化对象中,因为它看起来不错。STL对"<<"answers">>"使用重载也是出于同样的原因;他们认为这会让阅读变得更容易。

最近,我重载了一些算术运算符和"==",这样我就可以用数学符号写线性方程了。围绕这一点的代码从可读的源代码中构建系数矩阵,而不是要求开发人员编写一堆毫无意义的数字。这也是一个使用非恒定引用的例子——然而,所有这些的结果是表示方程的矩阵中的一行,所以这正是读者所期望的。

基本上,坚持一条重要的规则:永远不要做任何意想不到的事情。只有当结果符号(如"a+b")确实是不了解重载内部结构的人所期望的时,才重载运算符。

cpp的租户之一是用户类型的外观/行为应该类似于内置类型(如int)。

所以如果你能做

int a = 1;
int b = 2;
int c = a + b;

然后你也应该能够做

UserType e = ...;
UserType d = ...;
UserType f = e + d;

因此,运算符重载允许您为用户定义的类型定义运算符+/-*等,就像内置类型一样。。。

当您想要自然地表达某种类型的对象的某些方面时,它很有用。例如,编译器知道+、-、*、/如何应用于int和double。但它不知道+是如何应用于字符串(字符数组)的。它不能总是连接数组,因为这是无稽之谈。但对于特定的数组集(char数组),串联可以自然地用符号"+"表示,因此当我们编写(我们可能没有,因为我们有std::string)某个字符串类时,我们会重载运算符+(const MyString&rhs),它会将另一个字符串的内容添加到我们的字符串中。

但是运算符重载不仅可以用于您自己的类型。例如,您有一个表示IPv4地址的结构:

struct IpAddress
{
    unsigned int addr;
};

您需要一些东西,可以帮助您在屏幕上打印这个结构,或者将它写入文件。您可以添加函数to_str(),它将addr分解为4个组件并返回字符串表示,但更自然的方法是重载运算符<lt;ostream:

ostream& operator<<(ostream& os, const IpAddress& ip)
{
    os 
        << (ip.addr >> 24) << '.' 
        << (0xff & (ip.addr >> 16)) << '.'
        << (0xff & (ip.addr >> 8)) << '.'
        << (0xff & ip.addr); 
    return os;
}

所以现在您在将ip地址写入文件或屏幕时没有问题:

IpAddress ip;
// put something to ip
cout << "your address is: " << ip << endl;
ofstream f("log.txt");
f << "address: " << ip << endl;

非常自然。

p.s.当然假设sizeof(int)==4;)