数学运算符的成员函数与非成员函数


12

我正在编写一个线性代数库(长话短说,这是一个学校作业),它涉及矩阵,向量等。在创建该库的过程中,我将创建对对象执行数学运算的函数。例如,转置矩阵,反矩阵,归一化向量等。

我很好奇这种函数的“最佳实践”是什么...也就是说,我应该将该函数设为成员函数还是非成员函数?(为清楚起见/图书馆使用)

例:

//Member function way:
B = A.transpose();
C = A.inverse();

//Non-member function way:
B = linalg::transpose(A); //Non-member transpose function in linear algebra namespace
C = linalg::inverse(A);

关于这类操作是否有一些标准?或者至少,人们有一种通用的方式吗?我倾向于第一种选择,但我想知道是否建议这样做。

Answers:


7

这只是样式和品味的问题。我看过不同的线性代数库

  • 使用成员函数以OOP风格编写

  • 仅使用自由函数以非OOP样式编写

  • 同时提供API

他们都在工作。至少,您的API应该是一致的,因此请选择您的选择,并确保不要随意混合使用这些样式。


8

避免会员费:在可能的情况下,更希望使职能成为非成员非朋友。

非成员非友函数通过最小化依赖关系来改善封装:函数的主体不能依赖于类的非公共成员(请参见第11项)。它们还打破了整体类,以释放可分离的功能,从而进一步减少了耦合(请参见条款33)。它们提高了通用性,因为很难编写不知道某个操作是否是给定类型的成员的模板[...]

香草萨特


1
最后一个很好的答案:晚了,但还不算太晚。;-)另一个参考资料:GotW#84:整体式的“ Unstrung”
Deduplicator

1

成员功能和非成员功能除了单纯的品味外,还具有真正的优势。例如,用于实现matrix类的基础数组可能是private,因此,friend除非使用成员函数,否则必须使用。在这方面,OO设计可能更好。

但是,请记住,计算机科学家有时会必须执行复杂的数学公式,而又不总是知道您的实际工作。当我必须这样做时,我更喜欢非成员函数,因为“可视化”结果将更接近原始数学公式(因为数学公式通常使用函数样式)。

最后,答案与布朗博士的答案相同:这是一个品味问题。简而言之,您可以考虑编写一个具有成员函数的OO风格的库(易于编写,否friend),然后编写非成员函数来执行相同的任务,这些任务会将其参数直接转发给成员函数。它使您能够保持一致,并让用户选择他认为最好的内容。


0

如果您深入研究问题陈述,很明显,在某些时候,您将使用代表某些数学实体的自定义数据结构。例如,您可能用n维数组表示一个矩阵。为了详细说明您的示例,

// C way
typedef struct {
    int data[MAX_LEN][MAX_LEN];
} MATRIX;

MATRIX B = transpose(A);

// C++ way
class Matrix; // Forward Declaration
class Matrix {
    int data[MAX_LEN][MAX_LEN];
    public:
        Matrix transpose();
};

Matrix B = A.transpose();

(C ++示例已简化,可以使用模板等。)

要考虑的重点是在两种情况下都易于使用自定义数据结构。C ++(或任何面向对象的)作为一种语言本身具有更强大的功能,并扩展到库的使用者,这对实现者有利。过去,我只使用C语言的库,而这些自定义数据结构似乎无处不在!后者更容易实现互操作性(也许使用特殊的构造函数?)

为了解决这个问题,如果您使用的是C ++,那么绝对推荐使用面向对象的方法。


5
抱歉,您的推理几乎没有确凿的事实。两个transpose示例之间的易用性没有区别。C ++更容易的主要原因是因为复制和赋值语义实际上起作用。A = B可能会在C中编译,但可能做错了事。
MSalters 2014年

复制语义+1我试图解决的问题是使用对象(封装在“表示形式”上)v / s,它们使用松散耦合的结构集和相关功能。
dotbugfix 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.