【C++】static(静态)

类外

静态变量或函数意味着,当需要将这些变量或函数与实际定义的符号链接时,链接器不会在这个翻译单元的作用域之外寻找那个符号定义,即只会在这个翻译单元内部链接(文件内可用)

如果这句话并不理解,可以看一下【C++】How the C++ Compiler Works【C++】How the C++ Linker Works

示例:

Main.cpp

#include<iostream>
int s_Variable = 10;
int main() {
	std::cout << s_Variable << std::endl;
}

Static.cpp

static int s_Variable = 5;

没有问题,输出10

当删掉static int s_Variable = 5;中的static后,报错了

我们可以将int s_Variable = 10;改为extern int s_Variable;

没有问题,输出5

函数也是类似的,动手试一试吧

类内

静态成员:指的是在C++类中声明成员时,可以加上static关键字,这样声明的成员叫静态成员。静态成员分为静态数据成员和静态函数成员两种。

静态数据成员定义

class node{
    public:
    	static int id;//静态数据成员定义
};
int node::id=10;//静态数据成员类外初始化

静态数据成员的特点

  1. 类中的静态数据成员,所有对象都共享该数据,只有一份内存在内存中
  2. 类中的静态数据成员,必须要在类外初始化,因为它不属于对象,而是属于类。对象不管是否存在,这个静态数据成员都是存在的,而且静态数据成员的生命周期是程序开始就存在(主函数运行之前),直到程序结束才会被释放
  3. 类中的静态数据成员,可以在类中被重新赋值,可以被普通函数访问,如果该成员是公有属性,那么还可以在类外被对象自己访问(没什么意义),或者通过类名访问

静态函数成员定义

class node{
    public:
    	static void fun(){}//在类中定义
    	static void fun1();//在类中声明
};
void node::fun1(){}//在类外定义

静态函数成员的特点

  1. 类中的静态函数成员,这个函数同样也不属于对象,而是属于类的,所以在这个函数中不能操作类中的普通数据成员和普通成员函数。因为这些普通成员是必须要有对象的时候才会被建立,而静态函数不用对象也能调用
  2. 访问和静态数据成员一致
  3. 可以在这个静态函数中使用局部变量、形参、静态数据成员

示例:

#include<iostream>
struct Entity {
	int x, y;
	void print() {
		std::cout << x << "," << y << std::endl;
	}
};

int main() {
	Entity e;
	e.x = 2;
	e.y = 3;
	Entity e1;
	e1.x = 5;
	e1.y = 8;
	e.print();//2,3
	e1.print();//5,8
}

将x和y变为静态的:static int x, y;

并在结构体下面定义静态变量:

int Entity::x;
int Entity::y;

输出:

5,8
5,8

e1.x = 5;像这样引用没什么意义

可以像这样引用:Entity::x = 5;

同样地,将print函数改为静态的

e.print();可以写成Entity::print();

也就是说我们没有必要实例化对象就能使用静态变量和方法

那么,上面的代码可以改为

#include<iostream>
struct Entity {
	static int x, y;
	static void print() {
		std::cout << x << "," << y << std::endl;
	}
};
int Entity::x;
int Entity::y;
int main() {
	Entity::x = 6;
	Entity::y = 7;
	Entity::print();
}

上面我们说它们属于类,是指它们是类中的一部分,实质上它们和在命名空间中一样

如果我们让方法保持静态,变量不为静态,改成下面这样:

#include<iostream>
struct Entity {
	int x, y;
	static void print() {
		std::cout << x << "," << y << std::endl;
	}
};

int main() {
	Entity e;
	e.x = 6;
	e.y = 7;
	Entity::print();
}

出现报错:对非静态成员“Entity::x”的非法引用

你不能从静态方法访问它,因为静态方法没有类实例

局部静态(Local Static)

静态局部变量允许我们声明一个变量,它的生命周期基本上相当于整个程序的生命周期,但是它的作用域范围是被限制的。你可以在任何作用域中声明,如果在函数中声明,那么它的作用域范围被限制在这个函数中。

示例:

#include<iostream>
void Function() {
	static int i = 0;
	i++;
	std::cout << i << std::endl;
}

int main() {
	Function();
	Function();
	Function();
	Function();
	Function();
}

输出:

1
2
3
4
5

这意味着当我第一次调用函数时,这个变量将被初始化为0,然后所有对函数的后续调用实际上不会创建一个全新的变量

而下面这种情况就不会这样

#include<iostream>
void Function() {
	int i = 0;
	i++;
	std::cout << i << std::endl;
}

int main() {
	Function();
	Function();
	Function();
	Function();
	Function();
}

输出:

1
1
1
1
1

改变作用域范围也会达到同样的效果

#include<iostream>
int i = 0;
void Function() {
	i++;
	std::cout << i << std::endl;
}

int main() {
	Function();
	Function();
	Function();
	Function();
	Function();
}

输出:

1
2
3
4
5

但这种方法的问题是我可以在任意地方访问i

	Function();
	i=10;
	Function();
	Function();
	Function();
	Function();

输出:

1
11
12
13
14

示例——单例类

#include<iostream>
class Singleton {
private:
	static Singleton* s_Instance;
public:
	static Singleton& Get() {
		return *s_Instance;
	}
	void Hello() {
		std::cout << "Hello" << std::endl;
	}
};
Singleton* Singleton::s_Instance = nullptr;
int main() {
	Singleton::Get().Hello();
}

我们可以简化它

#include<iostream>
class Singleton {
public:
	static Singleton& Get() {
		static Singleton instance;
		return instance;
	}
	void Hello() {
		std::cout << "Hello" << std::endl;
	}
};
int main() {
	Singleton::Get().Hello();
}

这里就是作为例子,并没有完全达到单例模式的效果,可以进一步了解:【C++】单例模式


static的五种用法

  1. 全局变量前加static修饰为文件作用域全局变量,内存在全局数据区
  2. 块作用域前加static修饰为块作用域变量,但内存在全局数据区
  3. 普通函数前加static修饰为文件作用域函数
  4. 类中数据成员前加static修饰为类中所有对象共享数据
  5. 类中函数成员前加static修饰为类中所有对象共享成员
<think>好的,我现在需要帮助用户了解C++static静态函数的使用方法和特性。首先,我要回忆一下staticC++中的相关知识,确保自己理解正确。根据用户提供的引用内容,特别是引用[1]和引用[3],static成员函数是属于类而不是实例的,它们不能访问非静态成员,也不能使用this指针。另外,引用[3]中的例子展示了如何在静态函数中通过保存this指针来间接调用非静态成员函数,这可能是一个需要注意的点。 首先,我应该明确静态函数的基本定义和语法,比如在类内声明时使用static关键字,然后在类外定义时不需要重复static。同时,要强调静态函数只能访问静态成员变量或其他静态函数,不能直接访问类的非静态成员,这一点可能需要通过例子说明。 接下来,特性部分需要分点说明。比如,独立于实例、访问权限限制、作用域限定、回调函数中的应用等。每个特性都要结合引用中的例子,比如引用[1]提到的静态函数不依赖于实例,引用[3]中的回调函数使用静态函数并通过静态指针访问非静态成员。 然后,使用场景部分,可以举单例模式、工具类函数、回调函数封装等例子,这样用户能更好地理解何时使用静态函数。比如引用[3]中的例子,静态函数作为回调,通过保存的this指针调用成员函数,这在实际编程中很常见。 注意事项方面,要提到静态函数不能声明为const或volatile,因为它们没有this指针。另外,多线程环境下静态成员变量的同步问题也需要提醒用户注意,避免竞态条件。 用户可能的问题可能包括如何调用静态函数,与普通成员函数的区别,以及为什么静态函数不能访问非静态成员。这些问题需要提前预判,并在回答中涵盖。例如,调用方式可以通过类名直接调用,而无需实例,这点在引用[1]的示例中已经体现。 最后,生成相关问题时要围绕静态函数的相关知识点展开,比如与其他静态成员的关系、设计模式中的应用、多线程问题等,这样用户可以有进一步学习的方向。需要确保问题有针对性,帮助用户深入理解。 在整理回答时,要确保结构清晰,分点明确,每个部分都有引用支持,比如引用[1]、[3]的具体内容。同时,保持语言简洁,避免技术术语过多导致用户难以理解。可能还需要比较静态函数和普通成员函数的不同,帮助用户建立对比。 现在,需要检查是否有遗漏的重要点,比如静态函数的初始化、生命周期等,但根据用户提供的引用,可能不需要深入这些方面,主要聚焦在使用方法和特性上。因此,保持回答集中在用户的问题范围内,不扩展过多无关内容。 总结来说,回答的结构应该是:定义、使用方法、特性、使用场景、注意事项、示例代码、相关问题。每个部分都结合引用内容,确保准确性和相关性。这样用户能够系统地掌握static静态函数的关键知识点。</think>### C++ static静态函数的使用方法与特性 #### 一、静态函数的定义与使用方法 1. **语法格式** 在类内部声明时添加`static`关键字,类外定义时不再重复使用`static`: ```cpp class MyClass { public: static void myStaticFunction(); // 声明 }; // 定义时无需static void MyClass::myStaticFunction() { /*...*/ } ``` 2. **调用方式** - 通过类名直接调用:`MyClass::myStaticFunction();` - 通过对象调用(不推荐):`obj.myStaticFunction();` [^1] #### 二、核心特性 1. **独立于实例** 静态函数不依赖类的实例,无法访问非静态成员变量或函数,也不能使用`this`指针。 ```cpp class MathUtils { public: static int add(int a, int b) { return a + b; } // 仅依赖参数,不访问成员变量 }; ``` 2. **访问权限限制** - 只能访问类的**静态成员变量**或其他**静态函数**: ```cpp class Counter { static int count; // 静态成员变量 public: static void increment() { count++; } // 允许访问静态成员 }; ``` - 若需操作非静态成员,需通过传递对象指针/引用(如回调函数场景)[^3]。 3. **作用域限定** 静态函数受类作用域约束,可通过`类名::函数名`调用,避免命名冲突。 #### 三、典型应用场景 1. **工具类函数** 实现与类相关但无需实例的通用功能,例如数学计算、类型转换等。 ```cpp class StringConverter { public: static std::string toUpper(const std::string& s); }; ``` 2. **单例模式** 通过静态函数控制唯一实例的获取: ```cpp class Singleton { private: static Singleton* instance; Singleton() {} public: static Singleton* getInstance() { if (!instance) instance = new Singleton(); return instance; } }; ``` 3. **回调函数封装** 静态函数可作为C风格回调的入口,再通过静态指针调用成员函数: ```cpp class Timer { static Timer* instance; // 保存this指针 public: Timer() { instance = this; } static void callback() { instance->handleTimeout(); } // 委托给成员函数 void handleTimeout() { /*...*/ } }; ``` #### 四、注意事项 1. **与`const`的冲突** 静态函数不能声明为`const`或`volatile`(因无`this`指针)。 2. **多线程安全** 若静态函数操作静态成员变量,需通过锁(如`std::mutex`)保证线程安全。 #### 五、完整示例 ```cpp #include <iostream> class DataProcessor { private: static int processedCount; // 静态成员变量 public: static void processData(int x) { std::cout << "Processing data: " << x << std::endl; processedCount++; // 操作静态变量 } static int getCount() { return processedCount; } }; int DataProcessor::processedCount = 0; // 静态变量初始化 int main() { DataProcessor::processData(42); // 直接通过类名调用 std::cout << "Total processed: " << DataProcessor::getCount(); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值