学在前面
static关键字在C和C++编程中具有多种用途,根据上下文可改变其行为。下面从五个方面详细解释static关键字在这两种语言中的使用。
static关键字
1、概念
在C和C++中,static关键字用于声明变量或函数具有静态存储期。即这些变量或函数在程序的整个运行期间都存在,而不是作用域结束时被销毁。
2、为什么使用static
使用static关键字的主要原因包括:
延长变量生命周期:在函数内部声明的static变量,其生命周期会延伸到整个程序运行期间,而不仅仅是该函数被调用时。
限制变量作用域:在文件级(全局)作用域中使用static关键字可以限制变量或函数的作用域,使其仅在声明它的文件内部可见。
控制链接:控制变量或函数的链接属性,使其具有内部链接,即只能在定义它的文件内访问。
实现类成员变量的共享:在C++中,static成员变量被类的所有对象共享,而不是每个对象都有自己的副本。
3、如何使用static
3.1 修饰局部静态变量
在程序的整个运行期间只被初始化一次。
函数调用之间保持其值。
void func()
{
static int count = 0; // 只在第一次调用func时初始化,之后每次调用都会保留上一次的值
count++;
}
3.2 修饰全局静态变量
变量的作用域被限制在定义它们的文件内,其它文件不可见。
static int g_var = 10; // 仅在定义它的文件内可见
3.3 修饰函数
函数的作用域被限制在定义它们的文件内,其它文件不可见。
static void helperFunction(); // 仅在定义它的文件内可被调用
4、何时使用static
局部静态变量:当你需要一个在函数调用之间保持其值的变量时。
全局静态变量:当你需要一个仅在某个文件内使用的全局变量时。
静态函数:当你希望一个函数只在定义它的文件内可见时。
C++中的静态成员变量:当你需要一个类的所有对象共享的数据时。
C++中的静态成员函数:当你需要一个可以访问静态成员变量,但不依赖于特定对象实例的函数时。
5、优缺点
修饰对象 | 优点 | 缺点 |
局部变量 | 可以在函数调用之间保持状态。 | 可能导致资源泄漏或不必要的内存占用(如果变量占用了大量内存或资源)。 |
避免了重复初始化。 | 使得代码更加难以理解和调试,因为状态保持可能引入隐藏的错误。 | |
函数或全局变量 | 提供了封装和模块化,避免命名冲突。 | 限制了代码的可重用性和灵活性。 |
允许在不同的文件中定义同名变量或函数而不会互相干扰。 | 需要在多个文件中共享数据时,需要额外的机制(如通过接口函数或全局变量加extern)。 | |
类的数据 成员 | 允许所有对象共享同一个值。 | 访问静态成员变量需要通过类名或对象(尽管类名访问更常见),这可能使代码更加复杂。 |
可以用于实现类级别的计数器、缓存等。 | 需要特别注意多线程环境下的同步问题。 | |
类的函数 成员 | 可以用来实现与类相关的功能,但不需要访问对象的状态。 | 不能访问非静态成员变量或调用非静态成员函数,限制了其功能。 |
可以用于实现工厂方法、帮助函数等。 | 可能导致设计上的混淆,特别是如果静态成员函数和非静态成员函数具有相似名称时。 |
1、类的静态成员变量
类的静态成员变量可以是常量、引用、指针、类类型等类型,其属于类本身,不与任何类实例绑定。经常被用作类级别的默认值或计数器。
1.1 声明与定义静态成员变量
必须在类内声明,在类外定义,且只能被定义一次,定义时不加static关键字;其初始化不由构造函数完成。
class MyClass {
public:
static int sharedVar_; // 声明静态成员变量,在变量类型前加static
关键字
};
int MyClass::sharedVar_ = 0; // 定义静态成员变量,并进行初始化
1.2 如何使用静态成员变量
(1)通过类名访问
int value = MyClass::staticVar_;
(2)通过对象访问(不推荐,但语法上允许)
MyClass obj;
obj.staticVar_ = 5;
int value = obj.staticVar_;
(3)静态成员变量作为默认实参
class MyClass {
public:
constexpr static int DEFAULT_VALUE = 42;
void someMethod(int value = DEFAULT_VALUE) { }
};
1.3 静态成员变量的特征
共享性:所有对象共享同一个静态成员变量。即修改一个对象的静态成员变量会影响所有其它类实例(方便与风险并存)。
类作用域:静态成员变量在类作用域中定义,可以通过类名直接访问,也可以通过对象访问(但不推荐)。
初始化:静态成员变量必须在类外部进行初始化,而不能在类定义中直接初始化;C++11及更高版本允许在类内部初始化常量静态成员变量(但某些编译器可能仍然要求在类外部进行定义)。
生命周期:静态成员变量的生命周期贯穿整个程序运行期间,从程序开始到程序结束。
2、类的静态成员函数
2.1 声明静态成员函数
class MyClass {
public:
static void staticFunction()
{
// 可以直接访问静态成员变量,但不能直接访问非静态成员变量
sharedVar_++;
}
};
2.2 定义静态成员函数
静态成员函数在类内部或外部定义均可。若在类内部定义(即内联定义),则直接编写函数体即可;若在类外部定义,则需要使用“类名::”指定函数属于哪个类,不需要static关键字。
class MyClass {
public:
static void staticFunction(){
std::cout << "This is a static function." << std::endl; //类内定义
}
};
void MyClass::staticFunction(){
std::cout << "This is a static function (defined outside the class)." << std::endl; //类外定义
}
2.3 静态成员函数的特征
1、属于类本身
属于类本身,不是类的任何特定对象。因此,它们不能访问类的非静态成员变量。
2、无 this 指针
由于静态成员函数不属于任何对象,因此它们没有this指针。这意味着它们不能访问对象的成员变量(非静态的)或成员函数(非静态的,除非它们是 const 静态成员函数并且只访问 const 成员)。
3、直接通过类名调用
静态成员函数可以直接通过类名调用,而不需要创建类的对象。
4、只能访问静态成员
静态成员函数只能直接访问类的静态成员变量和其它静态成员函数。
5、不能声明为 virtual
静态成员函数不能是虚函数,因为虚函数机制依赖于对象的 this 指针,而静态成员函数没有this指针。