目录
01 前言
02 类内部创建静态变量的例子
03 在类的内部创建静态变量的作用
04 最后的话
01 前言
本期我们讨论 static 在一个类或一个结构体中的具体情况。
在几乎所有面向对象的语言中,静态在一个类中意味着特定的东西。这意味着在类的所有实例中,这个变量只有一个实例。如果我创建一个名为 Entity 的类,然后不断创建 Entity 实例,我仍然只会得到那个变量的一个版本。相对应的,如果某个实例改变了这个静态变量,它会在所有实例中反映这个变化。
正因为如此,通过类实例来引用静态变量是没有意义的。因为这就像是类的全局实例。
静态方法也是一样,无法访问类的实例。静态方法不需要通过类的实例就可以被调用。而在静态方法内部,你不能写引用到类实例的代码,因为你不能引用类的实例。
02 类内部创建静态变量的例子
让我们来看一下例子。
#include <iostream>
using namespace std;
class Dog
{
public:
int age;
const char *name;
void print()
{
cout <<name<<": "<<age << endl;
}
};
int main()
{
Dog dog;
dog.age = 10;
dog.name = "xiaohuan";
Dog dog2 = {15,"xiaobai"};
dog.print();
dog2.print();
return 0;
}
在这里我写一个叫做 Dog 类,一个整形变量age,一个常量指针name。
我们现在有一个非常简单的基类。并且实例化它,将其值设置为我们想要的值。
我想创建这个类的另一个实例,我也可以用第二种方法,然后用初始化器来完成初始化。
然后我们给了 Dog类的一个方法 Print。让两个实例分别调用 Print。
运行之后可以看到,结果很清楚,并没有什么问题。
如果我让变量变为静态的话,事情就会有些不一样了。
首先出现问题的地方是第二种初始化方法,x 和 y 变成静态的话,这样的初始化操作会失败,因为 x 和 y 不再是类成员。
我们先修改一下它。
我们有两个不同的实例,至少看起来是这样的。
如果我们运行代码,我们会得到一个错误。
编译器会告诉我们未定义变量,这是因为我们需要在某个地方定义那些静态变量。
我们可以这样操作。
现在链接器器可以连接到合适的变量了。
然后我们运行代码。
你会看到我们实际上打印了两次 一样的数据,结果有点奇怪。
我们回去看代码,首先我们在第一个实例上的设定了 10,xiaohuan。第二个为 12 和 xiaobai。然而你要记得,当 age 和 name 变成静态时,我们让这两个变量在 Entity 类的所有实例中只有一个实例。这意味着当我改变第二个 Dog实例的 x 和 y时,它们实际上和第一个完全是一样的,他们指向的是相同的内存。
没错,两个不同的 Dog实例,他们的 age 和 name指向同一个地方。这时候你就会明白,我们这样这样引用是没有意义的。
当然,如果让变量静态化之后,也可以这样初始化
就像我们在名为 Dog的命名空间中创建了两个变量,它们实际上并不属于类。
从严格意义上说它们可以是私有的,它们仍然是类的一部分,而不是命名空间的一部分。
但是无论出于何种目的,当你创建一个新的类的实例或类似的东西时,他们其实和在命名空间中是一样的。与如何分配无关。
03 在类的内部创建静态变量的作用
那么,这样做的意义是什么?
这当然很有用,当你想要跨类使用变量时,你可以使用一个静态全局变量而不使用全局变量,它是在内部进行链接的。不会在你这整个项目都是全局的。
那你为什么要这么做呢?答案是把他们放在 类中是有意义的。
举个例子,比如你想创建一个日志报表Log,其中有一条信息。你想要在所有的实例之间的共享数据。这时候将它存储在类中是有意义的,因为它与 Log有关。
要组织好代码,那你最好在这个类中创建一个静态变量,而不是一些静态的或全局的东西到处乱放。静态方法的工作方式与此类似,如果我让这个 Print 方法变成静态,它是会正常工作的。
看上述代码,我们在Log类中创建了一个messas字符串,然后我们在主函数将其初始化,初始化完将messags打印出来,很好,我们说过在类内部定义静态变量,其实所有的实例之间的数据数据是共享的,然后再在类的外部定义一个函数,在函数内将类的messags进行修改,最后在主函数打印出来。
04 最后的话
我希望我把相关的内容都讲清楚了。下期我们看看如何将许多的 static 知识整合了到我们一直在研究的 log 类中,看看那会变成是什么样子。
你可以先去看一下如何写一个 C++ 类那期。随着系列的进行,我们会继续增加 log 类的内容,并发掘一些我们可以做的新事情,并在学习新概念的同时不断改进它。
好了,记住,static 对于那些静态数据非常有用,这些数据不会在类实例之间发生变化。
本期的内容就是这些,下期再见。
Dog类相关代码
#include <iostream>
using namespace std;
class Dog
{
public:
static int age;
static const char *name;
static void print()
{
cout <<name<<": "<<age << endl;
}
};
static void print(Dog dog) //也可以这样使用类的静态变量
{
cout <<dog.name<<": "<<dog.age << endl;
}
int Dog::age; //定义变量,不然对象并不能找到定义,因为static相当于在类中能认识,但类的范围外并不认识
const char* Dog::name;
class Log
{
char *messages;
};
int main()
{
Dog dog;
dog.age = 10;
dog.name = "xiaohuan";
//Dog dog2;
Dog::age = 12;
Dog::name = "xiaobiao";
dog.print();
//dog2.print();
return 0;
}
Log 相关代码
#include <iostream>
using namespace std;
class Log
{
public:
static string messages;
static void print() //如果变量为非静态的话,则需要将类传进出,Log s ,s.messages
{
std::cout<< messages<<std::endl;
}
};
void print()
{
Log::messages = "this is from nothing funtion message";
}
string Log::messages;
int main()
{
Log::messages = "this is a test form main";
Log::print();
print();
Log::print();
return 0;
}