如何在C ++中创建静态类?我应该能够做类似的事情:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
假设我创建了BitParser
该类。会是什么BitParser
类的定义是什么样子?
如何在C ++中创建静态类?我应该能够做类似的事情:
cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;
假设我创建了BitParser
该类。会是什么BitParser
类的定义是什么样子?
Answers:
如果您正在寻找一种将“ static”关键字应用于类的方法(例如在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;
}
您可以使用此代码以与示例代码相同的方式调用方法。
希望有帮助!干杯。
private: BitParser() {}
这将阻止任何人创建实例。
BitParser() = delete;
正确传达删除构造函数的意图(而不仅仅是将其隐藏为private
)。
您想要的是用C ++语义表示的,将您的函数(因为它是一个函数)放在命名空间中。
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 ++中,这是不好的样式。
有人赞成使用静态方法,因为有时需要使用静态私有成员变量。
我有些不同意,如下所示:
// 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访问公共类的私有部分...),那private
是什么private
,即使它private
在标头中声明的类的部分中可见。
不过,如果您需要添加另一个可以访问私有成员的“私有函数”,则仍然必须通过修改标头向全世界进行声明,就我所知,这是一个悖论:如果我更改了我的代码(CPP部分),则界面(HPP部分)不应更改。引用利奥尼达斯的话:“ 这就是包囊! ”
什么时候类静态方法实际上比具有非成员函数的名称空间更好?
当您需要将功能分组在一起并将该分组输入模板时:
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 !!!
因为,如果类可以作为模板参数,则名称空间就不能。
#define private public
在标题中添加以下代码... ^ _ ^ ...
utilities
名称空间中所需的参数(不再需要)。这样,此功能可以进行单元测试,并且仍然没有对私有成员的特殊访问权限(因为它们是在函数调用时作为参数给出的)...
namespace
他们是否将无法访问您的global
成员(尽管隐藏)?显然,他们将不得不猜测,但是除非您有意混淆代码,否则变量名称非常容易猜测。
您还可以在名称空间中创建一个自由函数:
在BitParser.h中
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex);
}
在BitParser.cpp中
namespace BitParser
{
bool getBitAt(int buffer, int bitIndex)
{
//get the bit :)
}
}
通常,这是编写代码的首选方式。当不需要对象时,不要使用类。
如果您正在寻找一种将“ static”关键字应用于类的方法,例如在C#中
静态类只是编译器,它会牵着您的手,阻止您编写任何实例方法/变量。
如果您只是编写一个没有任何实例方法/变量的普通类,那是同一回事,这就是您在C ++中要做的
static
200次,这是一件好事。
我可以写类似的东西static class
吗?
否,根据C ++ 11 N3337标准草案附件C 7.1.1:
更改:在C ++中,静态或外部说明符只能应用于对象或函数的名称。在C ++中,将这些说明符与类型声明一起使用是非法的。在C语言中,将这些说明符用于类型声明时将被忽略。例:
static struct S { // valid C, invalid in C++ int i; };
原理:存储类说明符与类型关联时没有任何意义。在C ++中,可以使用静态存储类说明符声明类成员。允许在类型声明上使用存储类说明符可能会使用户感到困惑。
和一样struct
,class
也是类型声明。
可以通过遍历附件A中的语法树来推断出相同的含义。
有趣的是,这static struct
在C语言中是合法的,但没有效果:为什么以及何时在C语言编程中使用静态结构?
正如此处已指出的那样,在C ++中实现此目标的更好方法可能是使用名称空间。但是由于这里没有人提到final
关键字,因此我要发布static class
在C ++ 11或更高版本中与C#直接等效的内容:
class BitParser final
{
public:
BitParser() = delete;
static bool GetBitAt(int buffer, int pos);
};
bool BitParser::GetBitAt(int buffer, int pos)
{
// your code
}
这类似于C#在C ++中的实现方式
在C#file.cs中,您可以在公共函数中包含私有变量。在另一个文件中时,可以通过使用以下函数调用名称空间来使用它:
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();
命名空间对于实现“静态类”可能不那么有用的一种情况是使用这些类实现继承的组合。命名空间不能成为类的朋友,因此不能访问类的私有成员。
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
access修饰符声明一个伪纯虚函数。
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