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

时间:2020-03-05 18:39:17  来源:igfitidea点击:

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

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

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

解决方案

回答

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

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

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

回答

如果我们正在寻找一种将" static"关键字应用于类的方式(例如在Cfor中),那么如果不使用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;
}

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

希望对我们有所帮助!干杯。

回答

If you're looking for a way of applying the "static" keyword to a class, like you can in C# for example

静态类只是编译器,它会牵着手,阻止我们编写任何实例方法/变量。

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

回答

我们还可以在名称空间中创建自由函数:

在BitParser.h中

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

在BitParser.cpp中

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

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

回答

考虑马特·普赖斯(Matt Price)的解决方案。

  • 在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静态方法"模式的类更强大,因为:

  • 静态方法可以访问类的专用符号
  • 私有静态方法对所有人仍然可见(如果无法访问),这在某种程度上违反了封装
  • 静态方法不能被预先声明
  • 类用户不能在不修改库头的情况下重载静态方法
  • 在同一个名称空间中,静态方法无法完成比(可能是朋友)非成员函数更好的静态方法
  • 名称空间具有自己的语义(它们可以组合,也可以是匿名的,等等)
  • 等等。

结论:不要在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中)所有将被授权访问它的功能!!!

因此,使用私人静态成员就像裸照在外面走动,在皮肤上刺穿了恋人名单:没有人可以触摸,但每个人都可以窥视。好处是:每个人都可以拥有被授权与私人玩耍的人的名字。

确实是"私有" ...
:-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访问公共类的私有部分的方法……),否则" private"是`私有",即使它在标头中声明的类的"私有"部分中可见。

不过,如果我们需要添加另一个可以访问私有成员的"私有函数",则仍然必须通过修改标头向全世界进行声明,就我而言,这是一个悖论:如果我更改了实现,我的代码(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 ++中拥有一个静态类,静态类是一个没有实例化它的对象的类。在C ++中,这可以通过将构造函数/析构函数声明为私有来获得。最终结果是相同的。

回答

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

在Cfile.cs中,我们可以在public函数中包含private var。
在另一个文件中时,可以通过使用以下函数调用名称空间来使用它:

MyNamespace.Function(blah);

这是在C ++中实现相同效果的方法:

共享模块

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

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

共享模块

//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();

回答

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

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

... 迟到总比不到好...