C++ 静态成员效用函数与非成员效用函数

C++ 静态成员效用函数与非成员效用函数,c++,C++,我在这里读了一些其他问题,没有找到任何明确的答案 背景 打个比方,假设有一个节点类,我想从这个类中得到一个连接节点的图。为此,我需要一个函数get\u graph() 第一次尝试: 该函数是节点类的常规成员函数: class Node { //impl... GraphObj get_graph(); } class Node { //impl... static GraphObj get_graph(); } 我不喜欢这个,因为图形不是node类的功能。 这

我在这里读了一些其他问题,没有找到任何明确的答案

背景

打个比方,假设有一个节点类,我想从这个类中得到一个连接节点的图。为此,我需要一个函数
get\u graph()

第一次尝试:

该函数是
节点
类的常规成员函数:

class Node
{
    //impl...
    GraphObj get_graph();
}
class Node
{
    //impl...
    static GraphObj get_graph();
}
我不喜欢这个,因为图形不是node类的功能。 这是对
节点的一些实例的查询

第二次尝试:

该函数是
节点
类的静态成员函数:

class Node
{
    //impl...
    GraphObj get_graph();
}
class Node
{
    //impl...
    static GraphObj get_graph();
}
这更好,因为现在我已将函数与实例解耦。 但是,我仍然觉得这个函数是类的一部分并不舒服

第三次尝试:

该函数是同一命名空间/TU中的自由函数:

class Node
{
    //impl...
}
GraphObj get_graph(Node* graph_source);
现在它真的解耦了! 我不希望此类的用户错过此功能。 而且,这个函数只能作用于这个类,所以它会被过度解耦吗

tl;dr

您应该如何决定如何公开与类相关的函数? 特别是将功能公开为:

  • 常规成员函数
  • 静态成员函数
  • 获取类实例的自由函数
  • 还有别的吗
  • Scott Meyer关于成员与自由函数的论述在这里非常相关

    如果您正在编写一个可以作为成员或非友元非成员实现的函数,那么您应该更愿意将其作为非成员函数实现。这个决定增加了类封装

    查看文章中的解释

    成员函数是否应该是静态的是另一个问题。通常,如果它们没有耦合到特定实例,则将它们设置为
    静态
    。示例是用于根据构造函数参数设置对象状态的实用函数,例如

    A::A(int someArg) :
      dataMember{computeInitialState(someArg)}
    

    这里,
    computeInitialState
    应该是
    static
    。另一个例子是命名构造函数,例如,
    点::笛卡尔(双x,双y)
    -这也应该是
    静态的

    你有一个很好的问题,我必须说类比也很好。我将尝试解释什么时候使用什么,然后在最后,我们将研究什么适合这个用例

    何时使用常规成员函数

    这些是在对象级别工作的方法。典型的示例是用于获取/设置类属性值的getter和setter。构造函数也在对象级别工作(用一个值初始化它),因此它们也在类级别,本质上是非静态的

    何时使用静态成员函数

    给定类
    a
    ,如果类
    a
    的对象只需要该方法,则应将它们定义为静态成员。假设有一个
    isValid()
    方法。它只接受一个对象,并根据该对象是否具有所有有效值返回一个布尔值。此类方法应定义为类中的静态方法,因为有效性的定义可能远远超出空检查和空检查。下面是一个例子

    A类{
    public:int n1;//0)返回true;
    返回false;
    }
    };
    
    何时使用非成员方法

    如果有一个方法可以处理多个类的对象,那么应该将它们定义为非成员方法。这方面的一个例子是
    getValueOrDefault()
    方法,它可以按照下面的定义工作

    模板
    T GetValuerDefault(T n1,T n2){
    返回n1==NULL?n2:n1;
    }
    int main(){
    int num1=NULL,num2=2;
    
    我会和我的朋友一起做

    在任何情况下,如果您想要一些通用的东西,您需要有某种公共接口,可以是相同的成员名称或访问函数

    main.hh(或get_graph.hh)

    //
    #包括
    样板
    T&get_图(T&obj)
    {
    
    如果函数需要包含类定义中没有包含的内容,那么几乎可以肯定的是,你应该让它成为一个自由函数,以类的一个实例为例。你可能应该修改答案的开头。现在你似乎说,一般应该避免使用非静态成员函数。另外,你的示例f或者一个静态成员函数按值获取一个对象,然后将其与NULL(旧的NULL指针宏)进行比较。那里有问题。@besc感谢您建议进行编辑。更新了内容。