简体   繁体   English

你如何在 C++ 中创建一个静态类?

[英]How do you create a static class in C++?

How do you create a static class in C++?你如何在 C++ 中创建一个静态类? I should be able to do something like:我应该能够做这样的事情:

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

Assuming I created the BitParser class.假设我创建了BitParser类。 What would the BitParser class definition look like? BitParser类定义会是什么样子?

If you're looking for a way of applying the "static" keyword to a class, like you can in C# for example, then you won't be able to without using Managed C++.如果您正在寻找一种将“静态”关键字应用于类的方法,例如您可以在 C# 中,那么您将无法不使用托管 C++。

But the looks of your sample, you just need to create a public static method on your BitParser object.但是从示例的外观来看,您只需要在 BitParser 对象上创建一个公共静态方法。 Like so:像这样:

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;
}

You can use this code to call the method in the same way as your example code.您可以使用此代码以与示例代码相同的方式调用该方法。

Consider Matt Price's solution .考虑Matt Price 的解决方案

  1. In C++, a "static class" has no meaning.在 C++ 中,“静态类”没有意义。 The nearest thing is a class with only static methods and members.最接近的是一个只有静态方法和成员的类。
  2. Using static methods will only limit you.使用静态方法只会限制你。

What you want is, expressed in C++ semantics, to put your function (for it is a function) in a namespace.你想要的是,用 C++ 语义表达,把你的函数(因为它一个函数)放在一个命名空间中。

Edit 2011-11-11编辑 2011-11-11

There is no "static class" in C++. C++ 中没有“静态类”。 The nearest concept would be a class with only static methods.最近的概念是只有静态方法的类。 For example:例如:

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

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

But you must remember that "static classes" are hacks in the Java-like kind of languages (eg C#) that are unable to have non-member functions, so they have instead to move them inside classes as static methods.但是您必须记住,“静态类”是类 Java 语言(例如 C#)中的 hack,它们不能具有非成员函数,因此它们必须将它们作为静态方法移动到类中。

In C++, what you really want is a non-member function that you'll declare in a namespace:在 C++ 中,您真正想要的是在命名空间中声明的非成员函数:

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

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

Why is that?这是为什么?

In C++, the namespace is more powerful than classes for the "Java static method" pattern, because:在 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.等等。

Conclusion: Do not copy/paste that Java/C#'s pattern in C++.结论:不要在 C++ 中复制/粘贴 Java/C# 的模式。 In Java/C#, the pattern is mandatory.在 Java/C# 中,模式是必需的。 But in C++, it is bad style.但在 C++ 中,这是一种糟糕的风格。

Edit 2010-06-10编辑 2010-06-10

There was an argument in favor to the static method because sometimes, one needs to use a static private member variable.有一个支持静态方法的论据,因为有时需要使用静态私有成员变量。

I disagree somewhat, as show below:我有点不同意,如下所示:

The "Static private member" solution “静态私有成员”解决方案

// HPP

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

First, myGlobal is called myGlobal because it is still a global private variable.首先,myGlobal 之所以被称为 myGlobal,是因为它仍然是一个全局私有变量。 A look at the CPP source will clarify that:查看 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 !!!
}

At first sight, the fact the free function barC can't access Foo::myGlobal seems a good thing from an encapsulation viewpoint... It's cool because someone looking at the HPP won't be able (unless resorting to sabotage) to access Foo::myGlobal.乍一看,从封装的角度来看,免费函数 barC 无法访问 Foo::myGlobal 似乎是一件好事......这很酷,因为有人看着 HPP 将无法(除非诉诸破坏)访问Foo::myGlobal.

But if you look at it closely, you'll find that it is a colossal mistake: Not only your private variable must still be declared in the HPP (and so, visible to all the world, despite being private), but you must declare in the same HPP all (as in ALL) functions that will be authorized to access it !!!但是如果你仔细观察它,你会发现这是一个巨大的错误:不仅你的私有变量仍然必须在 HPP 中声明(因此,尽管是私有的,但对全世界都可见),而且你必须声明在同一个 HPP 中所有(如在 ALL 中)将被授权访问它的功能!!!

So using a private static member is like walking outside in the nude with the list of your lovers tattooed on your skin : No one is authorized to touch, but everyone is able to peek at.所以使用私人静态成员就像裸体走在外面,你的爱人名单纹在你的皮肤上:没有人被授权触摸,但每个人都可以偷看。 And the bonus: Everyone can have the names of those authorized to play with your privies.还有一个好处:每个人都可以拥有被授权与您的私人玩乐的人的名字。

private indeed... :-D确实是private ...... :-D

The "Anonymous namespaces" solution “匿名命名空间”解决方案

Anonymous namespaces will have the advantage of making things private really private.匿名命名空间的优势在于使私有的东西真正私有。

First, the HPP header一、HPP表头

// HPP

namespace Foo
{
   void barA() ;
}

Just to be sure you remarked: There is no useless declaration of barB nor myGlobal.只是为了确定您已经说过:barB 和 myGlobal 都没有无用的声明。 Which means that no one reading the header knows what's hidden behind barA.这意味着没有人阅读标题知道隐藏在 barA 后面的内容。

Then, the CPP:然后,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 !!!
}

As you can see, like the so-called "static class" declaration, fooA and fooB are still able to access myGlobal.如您所见,与所谓的“静态类”声明一样,fooA 和 fooB 仍然可以访问 myGlobal。 But no one else can.但没有其他人可以。 And no one else outside this CPP knows fooB and myGlobal even exist!在这个 CPP 之外没有其他人知道 fooB 和 myGlobal 甚至存在!

Unlike the "static class" walking on the nude with her address book tattooed on her skin the "anonymous" namespace is fully clothed , which seems quite better encapsulated AFAIK.不像“静态类”走在裸体上,她的地址簿纹身在她的皮肤上,“匿名”命名空间是完全覆盖的,这似乎更好地封装了 AFAIK。

Does it really matter?真的有关系吗?

Unless the users of your code are saboteurs (I'll let you, as an exercise, find how one can access to the private part of a public class using a dirty behaviour-undefined hack...), what's private is private , even if it is visible in the private section of a class declared in a header.除非您的代码的用户是破坏者(作为练习,我会让您找到如何使用肮脏的行为未定义的黑客访问公共类的私有部分......), privateprivate ,即使如果它在标头中声明的类的private部分中可见。

Still, if you need to add another "private function" with access to the private member, you still must declare it to all the world by modifying the header, which is a paradox as far as I am concerned: If I change the implementation of my code (the CPP part), then the interface (the HPP part) should NOT change.尽管如此,如果您需要添加另一个可以访问私有成员的“私有函数”,您仍然必须通过修改标题向全世界声明它,就我而言,这是一个悖论:如果我改变了我的代码(CPP 部分),那么接口(HPP 部分)不应该改变。 Quoting Leonidas : " This is ENCAPSULATION! "引用 Leonidas 的话:“这是封装!

Edit 2014-09-20编辑 2014-09-20

When are classes static methods are actually better than namespaces with non-member functions?什么时候类静态方法实际上比具有非成员函数的命名空间更好?

When you need to group together functions and feed that group to a template:当您需要将函数组合在一起并将该组提供给模板时:

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 !!!

Because, if a class can be a template parameter, a namespaces cannot.因为,如果一个类可以是模板参数,那么命名空间就不能。

You can also create a free function in a namespace:您还可以在命名空间中创建一个自由函数:

In BitParser.h在 BitParser.h 中

namespace BitParser
{
    bool getBitAt(int buffer, int bitIndex);
}

In BitParser.cpp在 BitParser.cpp 中

namespace BitParser
{
    bool getBitAt(int buffer, int bitIndex)
    {
        //get the bit :)
    }
}

In general this would be the preferred way to write the code.一般来说,这将是编写代码的首选方式。 When there's no need for an object don't use a class.当不需要对象时,不要使用类。

If you're looking for a way of applying the "static" keyword to a class, like you can in C# for example如果您正在寻找一种将“静态”关键字应用于类的方法,例如在 C# 中

static classes are just the compiler hand-holding you and stopping you from writing any instance methods/variables.静态类只是编译器牵着你,阻止你编写任何实例方法/变量。

If you just write a normal class without any instance methods/variables, it's the same thing, and this is what you'd do in C++如果你只是写一个没有任何实例方法/变量的普通类,那是一样的,这就是你在 C++ 中所做的

Can I write something like static class ?我可以写一些类似static class东西吗?

No , according to the C++11 N3337 standard draft Annex C 7.1.1:,根据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.更改:在 C++ 中,static 或 extern 说明符只能应用于对象或函数的名称。 Using these specifiers with type declarations is illegal in C ++.在 C++ 中将这些说明符与类型声明一起使用是非法的。 In C, these specifiers are ignored when used on type declarations.在 C 中,这些说明符在用于类型声明时会被忽略。 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.在 C++ 中,可以使用静态存储类说明符声明类成员。 Allowing storage class specifiers on type declarations could render the code confusing for users.允许在类型声明上使用存储类说明符可能会使用户感到困惑。

And like struct , class is also a type declaration.struct一样, class也是一个类型声明。

The same can be deduced by walking the syntax tree in Annex A.通过遍历附件 A 中的语法树可以推断出同样的情况。

It is interesting to note that static struct was legal in C, but had no effect: Why and when to use static structures in C programming?有趣的是, static struct在 C 中是合法的,但没有效果: 为什么以及何时在 C 编程中使用静态结构?

In C++ you want to create a static function of a class (not a static class).在 C++ 中,你想创建一个类的静态函数(不是静态类)。

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

You should then be able to call the function using BitParser::getBitAt() without instantiating an object which I presume is the desired result.然后,您应该能够使用 BitParser::getBitAt() 调用该函数,而无需实例化我认为是所需结果的对象。

As it has been noted here, a better way of achieving this in C++ might be using namespaces.正如这里所指出的,在 C++ 中实现这一点的更好方法可能是使用命名空间。 But since no one has mentioned the final keyword here, I'm posting what a direct equivalent of static class from C# would look like in C++11 or later:但是由于这里没有人提到final关键字,我发布了 C# 中static class的直接等效项在 C++11 或更高版本中的样子:

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

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

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

You 'can' have a static class in C++, as mentioned before, a static class is one that does not have any objects of it instantiated it.你可以在 C++ 中拥有一个静态类,如前所述,静态类是一个没有任何对象实例化它的类。 In C++, this can be obtained by declaring the constructor/destructor as private.在 C++ 中,这可以通过将构造函数/析构函数声明为私有来获得。 End result is the same.最终结果是一样的。

Unlike other managed programming language, "static class" has NO meaning in C++.与其他托管编程语言不同,“静态类”在 C++ 中没有任何意义。 You can make use of static member function.您可以使用静态成员函数。

In Managed C++, static class syntax is:-在托管 C++ 中,静态类语法是:-

public ref class BitParser abstract sealed
{
    public:
        static bool GetBitAt(...)
        {
            ...
        }
}

... better late than never... ... 迟到总比不到好...

This is similar to C#'s way of doing it in C++这类似于 C# 在 C++ 中的做法

In C# file.cs you can have private var inside a public function.在 C# file.cs 中,您可以在公共函数中使用私有变量。 When in another file you can use it by calling the namespace with the function as in:当在另一个文件中时,您可以通过使用以下函数调用命名空间来使用它:

MyNamespace.Function(blah);

Here's how to imp the same in C++:以下是如何在 C++ 中输入相同内容:

SharedModule.h共享模块.h

class TheDataToBeHidden
{
  public:
    static int _var1;
    static int _var2;
};

namespace SharedData
{
  void SetError(const char *Message, const char *Title);
  void DisplayError(void);
}

SharedModule.cpp共享模块.cpp

//Init the data (Link error if not done)
int TheDataToBeHidden::_var1 = 0;
int TheDataToBeHidden::_var2 = 0;


//Implement the namespace
namespace SharedData
{
  void SetError(const char *Message, const char *Title)
  {
    //blah using TheDataToBeHidden::_var1, etc
  }

  void DisplayError(void)
  {
    //blah
  }
}

OtherFile.h其他文件

#include "SharedModule.h"

OtherFile.cpp其他文件.cpp

//Call the functions using the hidden variables
SharedData::SetError("Hello", "World");
SharedData::DisplayError();

One (of the many) alternative, but the most (in my opinion) elegant (in comparison to using namespaces and private constructors to emulate the static behavior), way to achieve the "class that cannot be instantiated" behavior in C++ would be to declare a dummy pure virtual function with the private access modifier.一种(众多)替代方案,但最(在我看来)优雅(与使用命名空间和私有构造函数来模拟静态行为相比),在 C++ 中实现“无法实例化的类”行为的方法是使用private访问修饰符声明一个虚拟纯虚函数。

class Foo {
   public:
     static int someMethod(int someArg);

   private:
     virtual void __dummy() = 0;
};

If you are using C++11, you could go the extra mile to ensure that the class is not inherited (to purely emulate the behavior of a static class) by using the final specifier in the class declaration to restrict the other classes from inheriting it.如果您使用的是 C++11,您可以通过在类声明中使用final说明符来限制其他类的继承,以确保类不被继承(纯粹模拟静态类的行为)它。

// C++11 ONLY
class Foo final {
   public:
     static int someMethod(int someArg);

   private:
      virtual void __dummy() = 0;
};

As silly and illogical as it may sound, C++11 allows the declaration of a "pure virtual function that cannot be overridden", which you can use alongside declaring the class final to purely and fully implement the static behavior as this results in the resultant class to not be inheritable and the dummy function to not be overridden in any way.尽管听起来很愚蠢和不合逻辑,但 C++11 允许声明一个“不能被覆盖的纯虚函数”,你可以在声明类final同时使用它来纯粹和完全实现静态行为,因为这会导致结果类不可继承,并且虚拟函数不能以任何方式被覆盖。

// C++11 ONLY
class Foo final {
   public:
     static int someMethod(int someArg);

   private:
     // Other private declarations

     virtual void __dummy() = 0 final;
}; // Foo now exhibits all the properties of a static class

One case where namespaces may not be so useful for achieving "static classes" is when using these classes to achieve composition over inheritance.命名空间对于实现“静态类”可能不是那么有用的一种情况是使用这些类来实现继承上的组合。 Namespaces cannot be friends of classes and so cannot access private members of a class.命名空间不能是类的朋友,因此不能访问类的私有成员。

class Class {
 public:
  void foo() { Static::bar(*this); }    

 private:
  int member{0};
  friend class Static;
};    

class Static {
 public:
  template <typename T>
  static void bar(T& t) {
    t.member = 1;
  }
};
class A final {
  ~A() = delete;
  static bool your_func();
}

final means that a class cannot be inherited from. final意味着一个类不能被继承。

delete for a destructor means that you can not create an instance of such a class. delete析构函数意味着您不能创建此类类的实例。

This pattern is also know as an "util" class.这种模式也称为“util”类。

As many say the concept of static class doesn't exist in C++.正如许多人所说,C++ 中不存在static class的概念。

A canonical namespace that contains static functions preferred as a solution in this case.在这种情况下,首选包含static函数的规范namespace作为解决方案。

There is no such thing as a static class in C++. C++ 中没有静态类这样的东西。 The closest approximation is a class that only contains static data members and static methods.最接近的近似是一个只包含静态数据成员和静态方法的类。 Static data members in a class are shared by all the class objects as there is only one copy of them in memory, regardless of the number of objects of the class.类中的静态数据成员由所有类对象共享,因为它们在内存中只有一个副本,而不管类的对象数量如何。 A static method of a class can access all other static members ,static methods and methods outside the class类的静态方法可以访问所有其他静态成员、静态方法和类外的方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM