如何在c++中创建静态类?我应该可以这样做:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
假设我创建了BitParser类。BitParser类定义是什么样子的?
如何在c++中创建静态类?我应该可以这样做:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
假设我创建了BitParser类。BitParser类定义是什么样子的?
当前回答
class A final {
~A() = delete;
static bool your_func();
}
Final意味着一个类不能被继承。
析构函数的Delete意味着不能创建此类的实例。
此模式也称为“util”类。
正如许多人所说,静态类的概念在c++中并不存在。
在这种情况下,首选的解决方案是包含静态函数的规范名称空间。
其他回答
考虑一下马特·普莱斯的解决方案。
在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++中你“可以”有一个静态类,正如前面提到的,静态类是一个没有实例化它的任何对象的类。在c++中,可以通过将构造函数/析构函数声明为private来获得。结果是一样的。
名称空间对于实现“静态类”可能不太有用的一种情况是使用这些类实现继承上的组合。名称空间不能是类的友元,因此不能访问类的私有成员。
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;
}
};
你也可以在命名空间中创建一个自由函数:
在BitParser.h
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex);
}
在BitParser.cpp
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex)
{
//get the bit :)
}
}
一般来说,这是编写代码的首选方式。当不需要对象时,不要使用类。
在c++中实现“不能被实例化的类”行为的一种(众多)替代方法,但也是最优雅的(在我看来)方法(与使用名称空间和私有构造函数来模拟静态行为相比)是声明一个带有私有访问修饰符的虚拟纯虚函数。
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