矩阵模板类的重载运算符函数应该是友元还是成员

Should overloaded operator functions for matrix template class be friend or members

提问人:Renu 提问时间:6/6/2023 更新时间:6/8/2023 访问量:39

问:

虽然有很多关于使重载的运算符函数成为朋友或成员的帖子,但我仍然无法决定。我正在实现模板化矩阵类,主要用于算术运算,并且我以两种方式编写了重载运算符函数。让他们成为朋友的标准应该是什么?谢谢

C++ 模板 运算符重载 好友

评论

1赞 Richard Critten 6/6/2023
不是我复制的(我认为),但这包含一些很好的规则/指南/讨论 运算符重载的基本规则和习语是什么?我的看法是 (1) 对用户来说最不令人惊讶,并且 (2) 成员函数应该对对象进行操作,如果它们返回一个新对象,则使它们成为非成员。
1赞 Sam Varshavchik 6/6/2023
没有 C++ 的最高领袖坐在宝座上,祝福选定的实现技术并谴责所有其他技术。在这种情况下,通过充分了解每个备选方案的优缺点,然后选择特定于类、模板和应用程序代码的最佳备选方案,可以做出明智的决策。
1赞 BoP 6/6/2023
一个区别是,成员总是具有最左边的参数,而朋友可以具有不同的类型。这就是为什么不能成为班级的成员。thisoperator<<(ostream&, my_class)
0赞 Oersted 6/6/2023
我的经验法则是:朋友违反了封装,但有时是必要的。因此,首先我认为我的设计是为了不使用它。如果我必须将我的类内部暴露给某个函数或其他类,我会先尝试一个密钥环模式(不确定它是否是最佳链接)。只有在万不得已的情况下,我才会使用.friend
0赞 Oersted 6/6/2023
也许这个链接是为了细粒度的友谊。

答:

0赞 sigma 6/8/2023 #1

这主要是偏好和指南的领域,其中一些已经在评论中提到,还有一些列在我的首选建议 C++ 核心指南中。

不过,也有一些硬性限制。其中一个可能与您特别相关:假设您想允许标量数的乘法。基本类型甚至没有成员函数,因此,如果它们可以出现在左侧,则只能将运算符定义为非成员。但这同样适用于您自己无法修改的类,例如 .std::complex

如果该操作员还需要访问您不想公开的类的详细信息,那么唯一实际的选择就是让它成为朋友。这实际上保护了封装!

除了这些限制之外,好友声明还有一些好处。它允许您在类内联定义非成员函数,而不必在行外重复可能复杂的模板标头。这样的内联好友也被称为“隐藏好友”,因为它对普通的姓名查找是隐藏的。现在我们变得非常技术化,但这仍然会显着影响编译速度。

对于一些示例代码,我倾向于实现标量乘法的示例,如下所示:

template<number T, ...>
class Matrix
{
public:
    Matrix& operator*=(T const& rhs)
    { /* the actual operation */ }

    friend Matrix operator*(Matrix lhs, T const& rhs)
    {
        lhs *= rhs;
        return lhs;
    }

    friend Matrix operator*(T const& lhs, Matrix rhs)
    {
        return rhs * lhs;
    }
};

这里的名字只是一个合适概念的替身。目前,标准库中没有包含非基本算术类型的概念,因此您必须自己获取以允许复数。请注意,在此示例中,s 可能是常规非成员,我只是发现这种方式更方便和可读。numberoperator*