为什么/何时使用类数据成员而不定义该类的对象
Why/When would I want to use a class data member without defining an object of the class?
在C++中,可以使用一个类的数据成员,而不定义该类的对象,方法是在公共部分中将该数据成员定义为static
变量,如下面的代码示例所示。问题是,我为什么/什么时候想这样做?我该怎么做?
class ttime{
public:
ttime(int h=0, int m=0, int s=0):hour(h), minute(m), second(s){} //constructor with default intialization
int& warning(){return hour;}
void display()const{cout<<hour<<"t";}
static int hello;
~ttime(){}
private:
int hour;
int minute;
int second;
};
main()
{
ttime:: hello=11310; //Is this the way to use hello without creating an object of the class?
cout << ttime:: hello;
ttime hi(9);
hi.display();
hi.warning()++;//the user is able to modify your class's private data, which is really bad! You should not be doing this!
hi.display();
}
将类成员变量声明为static
本质上使其成为该类的所有实例共享的单例对象。这对于计数器、信号量和锁以及需要由其他类成员共享的其他类型的数据非常有用。
声明它为public
使该类的所有用户都可以访问它。不过,允许类变量由类外的函数修改通常是个坏主意。
另一方面,声明它为const
是为类提供公共可读常量的常用方法。
示例
您的图书馆类别:
class Foo
{
public:
// Version number of this code
static const int VERSION = 1;
private:
// Counts the number of active Foo objects
static int counter = 0;
public:
// Constructor
Foo()
{
counter++; // Bump the instance counter
...
}
// Destructor
~Foo()
{
counter--; // Adjust the counter
...
}
};
你图书馆的一些客户:
class Bar
{
public:
// Constructor
Bar()
{
// Check the Foo library version
if (Foo::VERSION > 1)
std::cerr << "Wrong version of class Foo, need version 1";
...
}
};
在本例中,VERSION
是类的一个静态常数,在这种情况下,它通知外部世界类中包含的代码版本。它是通过语法Foo::VERSION
访问的。
另一方面,静态counter
变量对类是私有的,因此只有Foo
的成员函数才能访问它。在这种情况下,它被用作活动Foo
对象数量的计数器。
如前所述,静态成员变量作为"全局"变量工作,但在类命名空间内。因此,它对于计数器或对象之间的共享资源非常有用。
在"public static"修饰符的情况下,很容易看到它在库中的使用,以提供对常量和通用功能(静态方法)的访问。
例如,一个输入库可能有:
class KeyEvent
{
public:
static const int KEY_DOWN = 111;
static const int KEY_UP = 112;
...
}
//And then in your code
#include <KeyEvent>
void poolEvent(Key *key)
{
if(key->type() == KeyEvent::KEY_DOWN)
...
}
我目前不熟悉静态的c++语法。但在c++-cli(.net,Visual c++)中,::
是正确的
用于静态:
在许多情况下,使用它们是有意义的。通常,当您希望存储属于类本身(意味着类的所有对象)而不是单个对象/实例的信息时。
尽管structs
的static
constexpr
数据成员最初并不是为此目的而发明的,但它们是模板元编程的支柱。只需查看limits
标准库头作为一个简单的示例。
例如,我们可以围绕内置的sizeof
运算符定义一个包装器。虽然它本身相当无用,但它有望给出正确的想法。
#include <iostream>
template<typename T>
struct Calipers
{
static constexpr auto size = sizeof(T);
};
int
main()
{
std::cout << "short: " << Calipers<short>::size << "n";
std::cout << "int: " << Calipers<int>::size << "n";
std::cout << "long: " << Calipers<long>::size << "n";
std::cout << "float: " << Calipers<float>::size << "n";
std::cout << "double: " << Calipers<double>::size << "n";
}
可能输出:
short: 2
int: 4
long: 8
float: 4
double: 8
它类似于全局变量,只是它没有在全局命名空间中定义。
您可以在引入名称空间之前编写的C++代码中找到它,或者在更有用的模板元编程中找到它。
总的来说,我不建议像您的例子那样使用它,并且希望尽可能避免全局状态。否则,您最终会得到难以测试的代码。
- 自定义对象的dlib序列化在gcc中失败
- 如何将带有自定义对象的容器从C++传递到QML
- 直接在 unordered_map 的方法中使用哈希,而不是生成哈希的用户定义对象
- 如何使用Q_PROPERTY公开自定义对象列表
- 如何在自定义对象的<<运算符中添加自定义前缀
- 将自定义对象作为参数从目标 C 传递到 C++
- 如何使用构造函数声明指向用户定义对象的指针?
- 使用自定义对象声明shared_ptr数组时出现错误 C2664
- 在具有自定义对象的集合中查找值
- std::set 不会检测到重复的自定义对象
- 如何使用自定义对象的序列化在 c++ 中编写自定义二进制文件处理程序
- std::排序为排序自定义对象时出现的向量引发错误
- 如何通过引用对用户定义对象的类型集 (STL) 的数组元素进行增强迭代?
- 具有自定义对象的C 优先级队列
- 自定义对象构造函数在循环外部循环
- 带有自定义对象的C 范围循环
- 为什么不允许通过 decltype(lamda) 定义对象,我该如何改进它?
- 如何正确地将规则 5(或零?)应用于包含带有字符串的自定义对象向量的类
- 编写安全包装类以管理用户定义对象的指针
- 如何在包含自定义对象的容器中使用分区函数C++