如何在c++中创建静态类?我应该可以这样做:

cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;

假设我创建了BitParser类。BitParser类定义是什么样子的?


当前回答

考虑一下马特·普莱斯的解决方案。

在c++中,“静态类”没有任何意义。最接近的是只有静态方法和成员的类。 使用静态方法只会限制你。

你想要的是,用c++语义表示,把你的函数(因为它是一个函数)放在一个命名空间中。

编辑2011-11-11

c++中没有“静态类”。最接近的概念是只有静态方法的类。例如:

// header
class MyClass
{
   public :
      static void myMethod() ;
} ;

// source
void MyClass::myMethod()
{
   // etc.
}

但是你必须记住,“静态类”是类java语言(例如c#)中的一种hack,它不能拥有非成员函数,所以它们必须将它们作为静态方法移动到类中。

在c++中,你真正想要的是在命名空间中声明的非成员函数:

// header
namespace MyNamespace
{
   void myMethod() ;
}

// source
namespace MyNamespace
{
   void myMethod()
   {
      // etc.
   }
}

为什么呢?

在c++中,命名空间比“Java静态方法”模式的类更强大,因为:

static methods have access to the classes private symbols private static methods are still visible (if inaccessible) to everyone, which breaches somewhat the encapsulation static methods cannot be forward-declared static methods cannot be overloaded by the class user without modifying the library header there is nothing that can be done by a static method that can't be done better than a (possibly friend) non-member function in the same namespace namespaces have their own semantics (they can be combined, they can be anonymous, etc.) etc.

结论:不要在c++中复制/粘贴Java/ c#的模式。在Java/ c#中,模式是强制的。但在c++中,这是糟糕的风格。

编辑2010-06-10

有一种观点支持静态方法,因为有时需要使用静态私有成员变量。

我有些不同意,如下所示:

“静态私有成员”解决方案

// HPP

class Foo
{
   public :
      void barA() ;
   private :
      void barB() ;
      static std::string myGlobal ;
} ;

首先,myGlobal被称为myGlobal是因为它仍然是一个全局私有变量。查看CPP源代码将澄清:

// CPP
std::string Foo::myGlobal ; // You MUST declare it in a CPP

void Foo::barA()
{
   // I can access Foo::myGlobal
}

void Foo::barB()
{
   // I can access Foo::myGlobal, too
}

void barC()
{
   // I CAN'T access Foo::myGlobal !!!
}

乍一看,自由函数barC不能访问Foo::myGlobal从封装的角度来看似乎是一件好事……这很酷,因为查看HPP的人将无法(除非诉诸于破坏)访问Foo::myGlobal。

但是如果你仔细观察它,你会发现这是一个巨大的错误:不仅你的私有变量仍然必须在HPP中声明(因此,尽管是私有的,但对所有人都是可见的),而且你必须在同一个HPP中声明所有将被授权访问它的函数!!

因此,使用一个私人静态成员就像裸体走在外面,皮肤上纹着你爱人的名单:没有人被授权触摸,但每个人都可以偷看。还有一个好处:每个人都可以知道那些有权玩弄你私处的人的名字。

私人确实…… : - d

“匿名命名空间”解决方案

匿名名称空间的优点是使内容成为真正的私有。

首先,HPP报头

// HPP

namespace Foo
{
   void barA() ;
}

只是为了确认您的评论:barB和myGlobal没有无用的声明。这意味着阅读标题的人不知道barA后面隐藏着什么。

然后,CPP:

// CPP
namespace Foo
{
   namespace
   {
      std::string myGlobal ;

      void Foo::barB()
      {
         // I can access Foo::myGlobal
      }
   }

   void barA()
   {
      // I can access myGlobal, too
   }
}

void barC()
{
   // I STILL CAN'T access myGlobal !!!
}

如您所见,与所谓的“静态类”声明一样,fooA和fooB仍然能够访问myGlobal。但没有人能做到。CPP之外的人甚至都不知道fooB和myGlobal的存在!

不像“静态类”裸体行走,她的地址簿纹在她的皮肤上,“匿名”命名空间是穿着衣服的,这似乎更好地封装了AFAIK。

这真的重要吗?

除非你的代码的用户是破坏者(我将让你作为练习,发现如何使用肮脏的行为-未定义的黑客访问公共类的私有部分…),私有的就是私有的,即使它在头文件中声明的类的私有部分可见。

尽管如此,如果你需要添加另一个“私有函数”来访问私有成员,你仍然必须通过修改头向所有人声明它,就我而言,这是一个悖论:如果我改变了我的代码的实现(CPP部分),那么接口(HPP部分)不应该改变。引用列奥尼达的话:“这就是封装!”

编辑2014-09-20

什么时候类静态方法实际上比带有非成员函数的名称空间更好?

当你需要将函数组在一起并将该组提供给模板时:

namespace alpha
{
   void foo() ;
   void bar() ;
}

struct Beta
{
   static void foo() ;
   static void bar() ;
};

template <typename T>
struct Gamma
{
   void foobar()
   {
      T::foo() ;
      T::bar() ;
   }
};

Gamma<alpha> ga ; // compilation error
Gamma<Beta> gb ;  // ok
gb.foobar() ;     // ok !!!

因为,如果一个类可以是模板形参,那么名称空间就不能。

其他回答

在c++中,你需要创建一个类的静态函数(不是静态类)。

class BitParser {
public:
  ...
  static ... getBitAt(...) {
  }
};

然后,您应该能够使用BitParser::getBitAt()调用函数,而无需实例化一个对象,我认为这是期望的结果。

与其他托管编程语言不同,“静态类”在c++中没有任何意义。可以使用静态成员函数。

我能写类似静态类的东西吗?

不,根据c++ 11 N3337标准草案附件C 7.1.1:

Change: In C ++, the static or extern specifiers can only be applied to names of objects or functions. Using these specifiers with type declarations is illegal in C ++. In C, these specifiers are ignored when used on type declarations. Example: static struct S { // valid C, invalid in C++ int i; }; Rationale: Storage class specifiers don’t have any meaning when associated with a type. In C ++, class members can be declared with the static storage class specifier. Allowing storage class specifiers on type declarations could render the code confusing for users.

和struct一样,class也是一种类型声明。

通过遍历附件A中的语法树也可以得出同样的结论。

有趣的是,静态结构在C语言中是合法的,但没有任何效果:为什么以及何时在C编程中使用静态结构?

如果您正在寻找一种将“static”关键字应用到类的方法,就像在c#中一样,那么如果不使用Managed c++,您将无法做到这一点。

但是从示例的外观来看,您只需要在BitParser对象上创建一个公共静态方法。像这样:

BitParser.h

class BitParser
{
 public:
  static bool getBitAt(int buffer, int bitIndex);

  // ...lots of great stuff

 private:
  // Disallow creating an instance of this object
  BitParser() {}
};

BitParser.cpp

bool BitParser::getBitAt(int buffer, int bitIndex)
{
  bool isBitSet = false;
  // .. determine if bit is set
  return isBitSet;
}

您可以使用此代码以与示例代码相同的方式调用该方法。

正如这里所指出的,在c++中实现这一点的更好方法可能是使用名称空间。但是因为没有人在这里提到最后一个关键字,所以我在这里发布的是c#中直接等价的静态类在c++ 11或更高版本中的样子:

class BitParser final
{
public:
  BitParser() = delete;

  static bool GetBitAt(int buffer, int pos);
};

bool BitParser::GetBitAt(int buffer, int pos)
{
  // your code
}