C++中仅包含静态方法的类的优势

45
尽管C++中 没有静态类,但来自Java背景的开发者常常会创建一个只包含静态方法的帮助类,比如Util。 这种做法是否被认为是不良代码风格还是通行做法?另一种可选方案是使用C函数(完全没有类上下文)。 其他有哪些替代方案?它们各自的优缺点是什么?在哪些情况下应该使用这些替代方案呢? 定义一组静态方法的C++建议将静态方法命名空间化作为一种替代方案,尽管我看不出在没有类上下文的情况下使用static关键字的效果是什么。

阅读您链接的帖子中Charles Bailey的答案。当应用于无类上下文的自由函数(没有类上下文的函数)与静态类成员函数时,static在C++中具有非常不同的含义。 - nos
8个回答

49

如果您想创建一组实用函数而不会覆盖全局命名空间,那么您应该在它们自己的命名空间中创建常规函数:

namespace utility {
    int helper1();
    void helper2();
};
你可能也不想将它们设为静态函数。 在C和C++中,当一个函数是非成员函数时(而不是成员函数),static关键字只是将函数的作用域限制在当前源文件中(也就是说,它使函数对当前文件私有)。它通常仅用于实现在C语言编写的库代码中使用的内部辅助函数,以便生成的辅助函数没有暴露给其他程序的符号。这对于防止名称冲突非常重要,因为C中没有命名空间。

9
对于那些从Java过渡到C++的人,需要注意的是正确的C++标准术语是“在非成员函数的上下文中(而不是成员函数)”。这并不意味着你必须遵循这种术语,但一些C++程序员(包括我在内)每次听到任何关于C++中的“方法”时都会有一个微小的“我们在谈论哪种语言?”的疑惑。 - Steve Jessop
1
@Steve,感谢您指出这一点! 它并不像您说的那么琐碎。 如果您知道某个东西的标准术语,那么您可以找到更好的答案,特别是如果您手头有一本书,并且正在使用索引来查找主题。 这也意味着对于许多C ++讨论,函数的概念在其他许多语言中通常称为方法或函数之间是重载的,因此知道在另一种语言中定义的“函数”更具体地是C ++中的“非成员函数”,这对我来说似乎相当重要。 - James O'Doherty

18

在C++中,仅具有static方法的类主要用于模板元编程。

例如,我想要在编译时计算斐波那契数列,并在运行时仅打印它们,那么我可以编写以下程序:

#include <iostream>

template<int N>
struct Fibonacci 
{
   static const int value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
   static void print()
   {
       Fibonacci<N-1>::print();
       std::cout << value << std::endl;
   }
};


template<>
struct Fibonacci<0>
{
   static const int value = 0;
   static void print()
   {
       std::cout << value << std::endl;
   }
};

template<>
struct Fibonacci<1>
{
   static const int value = 1;
   static void print()
   {
       Fibonacci<0>::print();
       std::cout << value << std::endl; 
   }
};

int main() {
        Fibonacci<20>::print(); //print first 20 finonacci numbers
        return 0;
}

在线演示:http://www.ideone.com/oH79u


3
我不确定“大多数”是否确实准确,我认为许多程序员使用静态类来逻辑地分组一组相关的函数(更好的选择是在命名空间中使用自由函数)。然而,你的回答是正确的,因为静态成员函数在TMP中被广泛使用。 - Luc Touraille
5
不要,不要再用那个费波纳奇数列的例子了! :) - Luc Touraille
@Luc:我认为很多程序员使用静态类来逻辑上组合一组相关功能。这是正确的,但这种情况相对较少见于元编程。 - Nawaz
2
我担心你可能高估了全世界C++程序员的技能,但这可能只是我的悲观在说话 :)。 - Luc Touraille

11

C++是一种多范式语言,因此如果您需要一些可能根本不适合于类的实用函数,那么我会将它们制作为自由函数。我认为没有理由仅仅为了OOP而将它们放入一个类中。

我看不出将所有函数都设为静态并将它们放入类中,与将它们作为自由函数的优势,个人认为自由函数是更易于使用的选项。


1
如果你想将函数分组,可以使用命名空间。 - Andreas Vinter-Hviid
2
我知道一个优点。如果你想让一组函数成为一个类的友元,把它们放在一个类中并将该类设为友元比分别将每个函数设为友元更容易且更加清晰。我所考虑的情况是工厂方法需要访问私有构造函数等。 - tokage
另一个优点是,您还可以定义私有静态辅助函数,以防多个实用函数具有共同的内部部分。 - gentooise

8

正如其他人所指出的那样,在中,将自由函数放在命名空间中是一种经常采用的方法。

当你想要暴露一组从模板参数派生的信息的函数集时,我会选择使用所有静态函数的类。

template <typename Ty>
    class utils
{
public :
// if you need to setup a bunch of secondary types, based on "Ty" that will be used 
// by your utility functions
    struct item_type
    { 
        Ty data;
        // etc
    }; 

// a set of utilities
    static void foo(Ty &data1, item_type &item)
    { 
        // etc
    }
};

你可以使用这个来实现模板化命名空间的效果:
int main ()
{
    double data;
    utils<double>::item_type item ;
    utils<double>::foo(data, item);

    return 0;
}

如果您没有使用模板,那就继续使用命名空间。
希望这能帮到您。

好的观点。这也类似于std::numeric_limits<>的实现。 - Walter

2

在类中声明静态方法没有实际问题。尽管如你所引用的帖子中所述,命名空间更适合此目的。

使用C函数可能会产生名称冲突,除非您决定使用命名约定,在函数前缀中加上一些内容,例如btFunctionA、btFunctionB等。您将希望将符号保持在命名空间中以避免这种情况发生,毕竟您使用的是C++而不是C。

命名空间中的静态函数与非静态函数没有任何区别。我相信在这种情况下static关键字被简单地忽略了。


2
在C++中,只需将它们作为自由函数即可。根本没有必要或原因将它们放在类中。除非你在使用模板进行编程。

1

还有一种情况,静态类可能比命名空间更合适:当您希望将数据设为私有,以便无法直接从类/命名空间外部修改,但出于性能原因,您希望拥有公共内联函数来操作它。我认为除了在命名空间中声明一个类之外,没有其他方法可以做到这一点。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接