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

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

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

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

543196 次浏览

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

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

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

如果你正在寻找一种应用“静态”的方法;关键字到一个类中,就像你在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;
}

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

如果你正在寻找一种将“static”关键字应用到类的方法,就像在c#中一样

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

如果你只是写一个普通的类,没有任何实例方法/变量,这是一样的,这就是你在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的解决方案

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

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

编辑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中声明所有将被授权访问它的函数!!

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

< p > private确实…… : - d < / p >

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

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

首先,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。

这真的重要吗?

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

尽管如此,如果你需要添加另一个访问私有成员的“私有函数”,你仍然必须通过修改头文件来向所有人声明它,这在我看来是一个悖论:

编辑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++中,可以通过将构造函数/析构函数声明为private来获得。结果是一样的。

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

在c# file.cs中,你可以在公共函数中使用私有变量。 当在另一个文件中,您可以通过如下函数调用命名空间来使用它:

MyNamespace.Function(blah);

下面是如何在c++中对相同的对象进行imp:

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

在Managed c++中,静态类语法是:-

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

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

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

我可以写类似static class的东西吗?

没有,根据c++ 11 N3337标准草案附录C 7.1.1:

在c++中,static或extern说明符只能应用于对象或函数的名称。 在c++中,将这些说明符与类型声明一起使用是非法的。在C语言中,这些说明符在使用时会被忽略 关于类型声明。例子:< / p >
static struct S {    // valid C, invalid in C++
int i;
};
原理:当与类型关联时,存储类说明符没有任何意义。在c++中,class 成员可以用静态存储类说明符声明。允许在类型上存储类说明符 声明可能会让用户对代码感到困惑

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

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

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

正如这里所指出的,在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
}

名称空间对于实现“静态类”可能不太有用的一种情况是使用这些类实现继承上的组合。名称空间不能是类的友元,因此不能访问类的私有成员。

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

在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
class A final {
~A() = delete;
static bool your_func();
}

final意味着一个类不能被继承。

析构函数的delete意味着你不能创建这样一个类的实例。

这种句型也被称为“util”;类。

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

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

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

之外的方法