c++ - 使用成员函数更改对象或返回它并分配它是否被认为是更好的做法?

标签 c++

首先,很抱歉,如果问题措辞不好,我不确定如何最好地措辞。另外我应该注意,我正在编写的代码是为了供其他人使用而设计的,因此可读性和易用性是关键。

假设我有一个类 vec3,它包含一个名为 Normalize 的成员函数。我看到如何操作此功能的两个选项。我可以使用该函数来规范化对象本身中包含的数据,或者我可以在函数内创建一个新的规范化 vec3 并返回它。

现在显然这两个函数都有它们的用途,但我想知道是否有针对此类事情的标准实践。显然返回一个新对象更灵活,因为我总是可以将新对象分配给该对象:

v = v.normalize();

vec3 vec3::normalize(){
    vec3 r = *this;
    double s = sqrt(r.x*r.x + r.y*r.y + r.z*r.z);
    if(s<1e-8){
        r.x=0.0; r.y=0.0; r.z=0.0;
    }
    else{
        x /= s;
        y /= s;
        z /= s;        
    }
    return r;

}

现在也许现代编译器可能会对此进行优化,但如果我几乎总是以这种方式使用这个函数,那么仅更改函数内的对象似乎更有效。

v.normalize()

void vec3::normalize(){
    double s = sqrt(x*x + y*y + z*z);
    if(s<1e-8){
        x=0.0; y=0.0; z=0.0;
    }
    else{
        x /= s;
        y /= s;
        z /= s;        
    }
}

现在我可以创建两个不同的函数,一个返回值,一个更改值,但是为每个函数执行此操作似乎有点矫枉过正,而且我不确定如何为用户区分它们。

现在显然很多这些问题都可以归结为程序员的个人喜好,但如果有针对此类问题的任何标准实践,我将非常感谢一些提示。

谢谢。

最佳答案

非常广泛地说,如果一个函数是一个成员函数,并且它的命名方式暗示了一个改变对象的操作,那么它可能会/应该这样做。 vector::clear 不返回空 vector ;它清除当前 vector 。

如果 vector 类型上有一个 normalize 函数,我想说人们会合理地假设它正在标准化 vector 本身。

现在,这几乎不具有普遍性。事实上,对于标准库来说,这甚至不是普遍适用的。 basic_string::substr 不会将字符串转换为其自身的子集;它返回一个新字符串,它是原始字符串的子集。

所以这通常是经销商的选择。但这并不意味着您的类的读者不会做出假设,并且一般的假设是看起来像它们会改变对象的成员函数可能会这样做。 a = a.normalize() 看起来有点奇怪。

相比之下,如果 normalize 是非成员函数,则可以合理地假设它返回归一化 vector ,而不是原位归一化 vector 。原因是,如果它原位突变,你将无法做这样的事情:

normalize(a + b);

人们通常会认为这会起作用。但如果它发生变异,它就不会发生变异;它将返回对临时对象的引用,该引用将在表达式末尾被销毁。

相比之下,(a + b).normalize()虽然在技术上是可行的,但看起来确实很奇怪,而且类似的事情几乎总是有代码味道。除非您稍后在同一表达式中使用该 vector ,否则您将获得对已销毁对象的引用。

这很糟糕。经验丰富的 C++ 程序员知道,几乎在每种情况下,类似这样的代码(在临时对象上调用成员函数)都在做坏事。

因此,如果您要使用变异成员函数,请记住两件事:使 (a + b).normalize() 无法编译,并返回 *this 放在最后,以便用户可以根据需要链接函数。例如:

vec3 &vec3::normalize() & //Prevents the use of this function on prvalues.
{
    double s = sqrt(x*x + y*y + z*z);
    if(s<1e-8){
        x=0.0; y=0.0; z=0.0;
    }
    else{
        x /= s;
        y /= s;
        z /= s;        
    }
    return *this;
}

关于c++ - 使用成员函数更改对象或返回它并分配它是否被认为是更好的做法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56616097/

相关文章:

c++ - 长行整数运算

c++ - 旋转和平移显示列表

c++ - 使用 Boost Spirit 提取未分隔的字符串和整数

C++虚拟运算符删除?

c++ - Brox 密集光流跟踪器错误 'EFilterIncompatibleSize'

c++ - ATL/COM : MIDL compiler doesn't output UUID for dispinterface

c++ - 在 OpenCV 中为 BRISK 设置参数

c++ - shared_ptr 在 if 条件下如何工作

c++ - 如何在内存数据库中创建多个SQLite