参考:视频 笔记
static基本分为两种,类外的static和类内的static:
在当前翻译单元中声明static变量,编译正常
由于关键字static,这个变量s_Variable只会在这个翻译单元内部链接。静态变量或函数意味着,当需要将这些函数或变量与实际定义的符号链接时,连接器不会再这个翻译单元的作用域之外,去寻找那个符号定义。
若不使用静态变量,则会出现链接的错误
因为这个s_Variable变量已经在另一个翻译单元(Main.cpp)中定义了,所以我们不能有两个同名的全局变量。
修改Main.cpp中这个变量的实际指向
去掉这里的赋值,标识这个变量为extern,这意味着它会在外部翻译单元中寻找s_Variable变量。
重新添加static属性
如果重新把Static.cpp里的变量标记为静态,这有点像在类中声明一个私有变量,其余所有的翻译单元都不能看到这个s_Variable变量,链接器在全局作用域下也不会看到。此时编译Main.cpp,会得到一个未解析的外部符号的错误,因为在任何地方都找不到名称为s_Variable的整型变量。
参考:视频 笔记(笔记写的很好很详细,可以好好看看)
静态成员变量是所有实例共享的,但是其只是在类中进行了声明,并未定义或初始化(分配内存),类或者类实例就无法访问静态成员变量,这显然是不对的。所以必须先在类外部定义,也就是分配内存。
静态成员变量在编译时存储在静态存储区,即定义过程应该在编译时完成。因此一定要在类外进行定义,但可以不初始化。
int Entity::x;
int Entity::y;
int main()
{
Entity e;
e.x = 2;
e.y = 3;
}
int Entity::x;
int Entity::y;
int main()
{
Entity::x = 2;
Entity::y = 3;
}
#include
struct Entity
{
static int x, y; // 类中静态变量的声明,但是还没有定义或初始化
void Print()
{
std::cout << x << "," << y << std::endl;
}
};
// 在类外对类内的静态变量进行定义,这里可以不初始化,也可以初始化
int Entity::x;
int Entity::y;
int main()
{
// 访问方法1:使用类的示例进行访问
Entity e;
e.x = 2;
e.y = 3;
// 访问方法2:使用类名进行访问,类似命名空间
Entity::x = 6;
Entity::y = 7;
std::cin.get();
}
如果我们让x,y变量是非静态的,这样对Entity类的每个实例都有一个单独的x和y,print方法仍然保持static。但静态方法不能访问非静态变量。
因为静态方法没有类实例。本质上在类中写的每一个方法,每一个非静态方法总是获得当前类的一个实例作为参数,这是类在幕后的实际工作方法。它们通过隐藏参数(this指针)发挥作用,静态方法不会得到那个隐藏参数。
参考:视频 笔记(写的很好,可以细看)
在局部作用域中声明为static,被标记为static的变量i生存周期基本和程序相同,并且它被限制在了Func()中,这样就不用把i定义成全局变量了。
这样就可以调用Singleton::Get得到一个单例对象了。
#include
class Singleton
{
private:
// 静态成员变量,Singleton类型的指针实例
static Singleton* s_Instance;
public:
// 返回Singleton类型的实例的引用,注意这里用了解引用符号*,就是为了得到类,而不是类的指针
static Singleton& Get() { return *s_Instance; };
void Hello()
{
std::cout << "Hello" << std::endl;
}
};
// 这里是对类中的静态成员变量进行定义和初始化
// Singleton*声明了静态成员变量的类型,Singleton::s_Instance声明了是哪个类中的哪个静态成员变量,最后nullptr是初始化
Singleton* Singleton::s_Instance = nullptr;
int main()
{
// Singleton::Get()就得到一个单例的对象,由于是类似命名空间直接调用类的方法得到的,而不是对象的方法,因此只有一个实例
Singleton::Get().Hello();
std::cin.get();
}
如果这里没有static关键字,那么这个单例会在栈上创建,函数作用域结束时就会被销毁。通过添加静态让它的生存期延长到永远。意味着我们每次调用Get,它实际上会构造一个单例实例,接下来的时间只会返回这个已经存在的实例,而不会每次调用Get的时候都重复定义这个实例再返回。(本质上和函数内的local static是一样的道理)
#include
class Singleton
{
public:
// 返回Singleton类型的实例的引用
static Singleton& Get()
{
static Singleton instance; // 这里的static关键字很重要,和函数中的local static是一样的功能
return instance;
};
void Hello()
{
std::cout << "Hello" << std::endl;
}
};
int main()
{
// Singleton::Get()就得到一个单例的对象,由于是类似命名空间直接调用类的方法得到的,而不是对象的方法,因此只有一个实例
Singleton::Get().Hello();
std::cin.get();
}