重载操作符来处理我自己的类作为std类是一个好做法吗?

Is overloading operators to handle my own classes as std classes a good practice?

本文关键字:一个 处理 操作符 我自己 自己的 std 重载      更新时间:2023-10-16

我一直在阅读Deitel的c++ Fundamentals, Deitel先生着重于重载标准操作符,以便为自定义类及其成员提供标准功能。我的意思是,例如,我可以直接说cout << object;

而不是cout << object.memberFunction();

这种技术确实允许链接和更快的输入,但它需要操作符重载实现,即使我仍然是一个新手,我觉得代码实际上使可读性降低,特别是如果有许多类成员你必须记住哪些是操作符重载的等等。没有重载操作符的代码可读性更强,而且可以节省重载代码。

所以我的问题是我是否应该花时间学习操作符重载?我是c++的新手,欢迎有更多实践和经验的人给出答案。操作符重载的好处会超过实现它所付出的努力和降低的代码可读性吗?

您当然应该花时间学习操作符重载。然而,这并不意味着你应该或不应该使用操作符重载。但没有学习,你就无法真正做出决定。决定使用你不熟悉的东西即使不是不可能,也是很困难的。你总是会发现一些你不知道的东西更难用,即使它实际上更容易。

也就是说,根据具体情况做你认为最好的事情。如果在您的情况下,您发现操作符重载使代码可读性降低,那么无论如何都不要这样做。然而,在某些情况下它是有用的。但是,由于重载操作符通常是出于可读性的目的,如果您发现它不适用于您的情况,请远离它。

我很想说,没有什么可以学习的操作符重载;重载操作符只是有趣的命名函数。什么你必须知道什么时候超载是合适的,什么时候是合适的不是。某些习惯用法或多或少是标准的:数字类型重载适当的数字运算符(+等),智能指针过载指针操作(*->),支持索引的容器类型重载[]和函数对象重载()。这就是它适用于特殊情况。虽然这可以说是一种虐待,但如果你定义迭代器时,您将希望它支持标准迭代器成语(即++*->==/!=)。

除了这些,还有三个操作符将被重载对于许多不同类型的类:赋值是使用=和使用<<>>完成流的插入和提取。如果您希望您的类支持其中的任何一种,您应该使用过载。比较用==!=表示相等,<<=, >>=为不等式。但不要因为不平等而超载除非它在语义上是重要的。最好提供一个用于std::mapstd::set的显式排序函数误导读者,让他们认为你已经在语义上定义了重要的排序。您可能需要将std::less专门用于您的类在这种情况下;<将不起作用,或者将有不适当的语义作为键使用,但是std::less将定义一个任意的排序这将。虽然不是操作符重载,但如果类型是作为关联容器中的键,您还需要提供函数hash_codestruct std::hash的实例化。

在许多情况下,最好用some more来定义重载全局函数:例如:我使用compare(返回int)大于,等于或大于0),表示不相等;我将定义一个public函数compare,然后派生如下:
template<typename T>
struct ComparisonOperators
{
    friend bool operator==( T const& lhs, T const& rhs )
    {
        return lhs.compare() < 0;
    }
    //  ...
    //  The same for the other five operators.
};

(我的实现实际上有点复杂,因为它使用元编程为==!=使用isEqual,如果类提供它。)

我对二进制算术运算符使用了类似的技术,定义用+=来表示+,等等。我还将它用于IO,用术语定义<<print>>parse的比值;这主要用于操作符需要是多态的

操作符重载在很多情况下可以提高可读性,在这些情况下它是有用的。你可能第一次遇到了一个不幸的例子;特别是对于操作符<<,就会发生这种情况,您已经学到了操作符重载的第一个教训:有时,显式方法调用更清晰。但有时并非如此。例如,考虑c++中一个典型的矩阵乘法(例如使用特征矩阵):

a = b * c;

和Java中的

a = b.multiplyUsingTheMatrixMultiplicationAlgorithmThatsMathYay(c);

操作符重载使代码更具可读性。对于这些情况,您应该学习或至少了解操作符重载,并且只有在这些情况下才应该应用它。

实际上,我认为标准的重载操作符是理所当然的,并没有考虑到每种类型都有单独的实现。操作符重载在很多方面都很重要,比如在使用模板的时候,节省的时间比我最初意识到的要多得多。

通常使用友外部操作符,如下所示

friend std::ostringstream & operator<<(std::ostringstream &oss, Type &type);

std::ostringstream & operator<<(std::ostringstream &oss, Type &type)
{
    oss << type.attr1;
    oss << type.attr2;
    oss << type.attr3;
    return oss;
}

所以你可以这样调用:

Type val;
...
std::cout << val << std::end;
相关文章: