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

时间:2008-08-12 23:35:01

标签: c++ oop class syntax static

如何在C ++中创建静态类?我应该能够做到这样的事情:

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

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

15 个答案:

答案 0 :(得分:248)

如果您正在寻找一种将“static”关键字应用于类的方法,例如您可以在C#中使用,那么您将无法使用托管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;
}

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

希望有所帮助!欢呼声。

答案 1 :(得分:231)

考虑Matt Price's solution

  1. 在C ++中,“静态类”没有意义。最接近的是一个只有静态方法和成员的类。
  2. 使用静态方法只会限制你。
  3. 你想要的是,用C ++语义表达,将你的函数(对于它一个函数)放在命名空间中。

    编辑2011-11-11

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

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

    但是你必须记住,“静态类”是类似Java的语言(例如C#)中的黑客,它们不能拥有非成员函数,所以他们反而将它们作为静态方法移动到类中。 / p>

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

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

    为什么?

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

    • 静态方法可以访问类私有符号
    • 私有静态方法仍然可见(如果无法访问)给每个人,这有点违反了封装
    • 静态方法不能正向声明
    • 类用户无法在不修改库标题的情况下重载静态方法
    • 没有什么可以通过静态方法完成,这种方法不能比同一命名空间中的(可能是朋友的)非成员函数做得更好
    • 命名空间有自己的语义(它们可以组合,它们可以是匿名的等等)。

    结论:不要在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中声明所有(将在ALL中)有权访问它的函数!!!

    所以使用私人静态成员就像走在外面裸体一样,你的爱人的名单纹在你的皮肤上:没有人有权触摸,但每个人都可以偷看。奖金:每个人都可以拥有被授权与你的私人玩耍的人的名字。

    确实...... private :-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。

    真的重要吗?

    除非你的代码的用户是破坏者(我会让你,作为练习,找到如何使用脏行为 - 未定义的hack来访问公共类的私有部分......),{{ 1}}是private,即使它在标题中声明的类的private部分中可见。

    但是,如果你需要添加另一个“私有函数”来访问私有成员,你仍然必须通过修改标题向全世界声明它,就我而言这是一个悖论:如果我改变了我的代码(CPP部分)的实现,那么界面(HPP部分)就不应该改变。引用Leonidas:“这是封锁!

    编辑2014-09-20

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

    当您需要将功能组合在一起并将该组提供给模板时:

    private

    因为,如果类可以是模板参数,则命名空间不能。

答案 2 :(得分:60)

您还可以在命名空间中创建自由函数:

在BitParser.h中

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

在BitParser.cpp中

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

通常,这是编写代码的首选方法。当不需要对象时,不要使用类。

答案 3 :(得分:12)

  

如果您正在寻找一种将“static”关键字应用于类的方法,例如您可以在C#中使用

静态类只是编译器手持您并阻止您编写任何实例方法/变量。

如果你只是编写一个没有任何实例方法/变量的普通类,那就是同样的事情,这就是你在C ++中所做的事情

答案 4 :(得分:11)

在C ++中,您想要创建一个类的静态函数(而不是静态类)。

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

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

答案 5 :(得分:10)

我可以写一些类似static class的内容吗?

,根据C++11 N3337 standard draft附件C 7.1.1:

  

更改:在C ++中,静态或外部说明符只能应用于对象或函数的名称。   在C ++中使用带有类型声明的这些说明符是非法的。在C中,使用时会忽略这些说明符   在类型声明。例如:

static struct S {    // valid C, invalid in C++
  int i;
};
     

基本原理:与类型关联时,存储类说明符没有任何意义。在C ++中,类   可以使用静态存储类说明符声明成员。允许类型的存储类说明符   声明可能会使代码对用户造成混淆。

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

通过走附录A中的语法树可以推断出相同的结果。

有趣的是,static struct在C中是合法的,但没有效果:Why and when to use static structures in C programming?

答案 6 :(得分:5)

你可以'在C ++中拥有一个静态类,如前所述,静态类是没有任何实例化它的对象的类。在C ++中,这可以通过将构造函数/析构函数声明为私有来获得。最终结果是一样的。

答案 7 :(得分:4)

在托管C ++中,静态类语法为: -

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

......迟到总比没有好......

答案 8 :(得分:3)

这类似于C#在C ++中的方式

在C#file.cs中,您可以在公共函数中包含private var。 在另一个文件中,您可以通过使用以下函数调用命名空间来使用它:

MyNamespace.Function(blah);

以下是如何在C ++中使用它:

<强> SharedModule.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

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

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

答案 9 :(得分:3)

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

答案 10 :(得分:2)

(许多)替代方法中的一种,但最优雅的方法(在我看来)(与使用名称空间和私有构造函数来模拟静态行为相比),是在C ++中实现“无法实例化的类”行为的方式将使用private访问修饰符声明一个虚拟的纯虚函数。

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

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

如果您使用的是C ++ 11,则可以通过在类声明中使用final说明符来加倍努力以确保该类不被继承(以纯粹模拟静态类的行为)。限制其他类继承它。

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

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

尽管听起来很愚蠢和不合逻辑,但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

答案 11 :(得分:2)

正如此处所述,在C ++中实现此目的的更好方法可能是使用命名空间。但由于此处没有人提到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
}

答案 12 :(得分:0)

class A final {
  ~A() = delete;
  static bool your_func();
}

final 表示一个类不能被继承。

delete 对于析构函数意味着您不能创建此类类的实例。

这种模式也称为“util”类。

正如许多人所说的,C++ 中不存在 static class 的概念。

包含 namespace 函数的规范 static 在这种情况下首选作为解决方案。

答案 13 :(得分:0)

C++ 中没有静态类这样的东西。最接近的近似是一个只包含静态数据成员和静态方法的类。 类中的静态数据成员由所有类对象共享,因为它们在内存中只有一个副本,而不管类的对象数量如何。 类的静态方法可以访问所有其他静态成员、静态方法和类外的方法

答案 14 :(得分:0)

命名空间可能对实现&#34;静态类&#34;无效的一种情况。是在使用这些类来实现组合而不是继承时。命名空间不能成为类的朋友,因此无法访问类的私有成员。

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