当前位置: 首页 > news >正文

第二十六天:static、const、#define的用法和区别

static、const、#define的用法和区别

1. static的用法

  • 修饰局部变量:当static修饰局部变量时,该变量的生命周期会延长至整个程序运行期间,但其作用域仍局限于声明它的函数内部。每次函数调用时,其值会保留上次调用结束时的值。例如:
#include <iostream>
void test() {static int count = 0;count++;std::cout << "Count: " << count << std::endl;
}
int main() {for (int i = 0; i < 3; i++) {test();}return 0;
}

在上述代码中,count是一个静态局部变量,每次调用test函数时,count的值都会增加,并且在函数调用之间保持其值。输出结果为:

Count: 1
Count: 2
Count: 3
  • 修饰全局变量:当static修饰全局变量时,该变量的作用域被限制在定义它的源文件内,其他源文件无法访问。这有助于避免全局变量命名冲突。例如,在file1.cpp中定义static int globalStaticVar = 10;,在file2.cpp中无法直接访问globalStaticVar
  • 修饰成员变量:在类中,static修饰的成员变量为所有类对象所共享,不属于任何一个具体对象。它在类的所有对象之间是唯一的,存储在全局数据区,而不是对象的内存空间中。例如:
#include <iostream>
class MyClass {
public:static int sharedVar;
};
int MyClass::sharedVar = 0;
int main() {MyClass obj1, obj2;obj1.sharedVar = 1;std::cout << "obj1.sharedVar: " << obj1.sharedVar << std::endl;std::cout << "obj2.sharedVar: " << obj2.sharedVar << std::endl;return 0;
}

在上述代码中,sharedVarMyClass类的静态成员变量,通过一个对象修改sharedVar的值,其他对象访问时也会看到相同的变化。输出结果为:

obj1.sharedVar: 1
obj2.sharedVar: 1
  • 修饰成员函数static修饰的成员函数只能访问静态成员变量和其他静态成员函数,不能访问非静态成员变量,因为非静态成员变量依赖于具体的对象实例,而静态成员函数不依赖于任何对象实例。例如:
#include <iostream>
class MyClass {
public:static int sharedVar;static void staticFunction() {sharedVar++;std::cout << "Shared variable in static function: " << sharedVar << std::endl;}
};
int MyClass::sharedVar = 0;
int main() {MyClass::staticFunction();return 0;
}

在上述代码中,staticFunction是一个静态成员函数,它可以访问和修改静态成员变量sharedVar

2. const的用法

  • 修饰变量const修饰的变量为常量,其值一旦初始化后就不能再改变。例如:
const int num = 10;
// num = 20; // 错误,不能修改常量的值
  • 修饰指针const修饰指针时有两种情况,一种是指向常量的指针(const int* ptr),指针指向的值不能通过该指针修改,但指针本身可以指向其他地址;另一种是常量指针(int* const ptr),指针本身不能再指向其他地址,但指针指向的值可以修改。例如:
const int num1 = 10;
int num2 = 20;
const int* ptr1 = &num1;
// *ptr1 = 30; // 错误,不能通过指向常量的指针修改值
ptr1 = &num2; // 正确,指针可以指向其他地址int* const ptr2 = &num2;
*ptr2 = 30; // 正确,常量指针指向的值可以修改
// ptr2 = &num1; // 错误,常量指针不能再指向其他地址
  • 修饰成员函数:在类中,const修饰的成员函数不能修改类的非静态成员变量,常用于只读取数据而不修改数据的函数。例如:
#include <iostream>
class MyClass {
private:int data;
public:MyClass(int value) : data(value) {}int getData() const {// data = 10; // 错误,不能在 const 成员函数中修改非静态成员变量return data;}
};
int main() {MyClass obj(5);std::cout << "Data: " << obj.getData() << std::endl;return 0;
}

在上述代码中,getData是一个const成员函数,它保证不会修改MyClass类的非静态成员变量data

  • 修饰对象const修饰的对象只能调用const成员函数,因为非const成员函数可能会修改对象的状态。例如:
const MyClass constObj(10);
// constObj.getData(); // 正确,调用 const 成员函数
// constObj.setData(20); // 错误,如果有 setData 非 const 成员函数,不能调用

3. #define的用法

  • 定义常量#define可以用来定义宏常量,在预处理阶段,预处理器会将代码中出现的宏常量替换为其定义的值。例如:
#define PI 3.14159
#include <iostream>
int main() {double radius = 5.0;double area = PI * radius * radius;std::cout << "Area of circle: " << area << std::endl;return 0;
}

在上述代码中,PI是一个宏常量,预处理器会在编译前将代码中的PI替换为3.14159

  • 定义宏函数#define还可以定义宏函数,它与普通函数类似,但在预处理阶段进行文本替换,没有函数调用的开销。例如:
#define MAX(a, b) ((a) > (b)? (a) : (b))
#include <iostream>
int main() {int num1 = 5, num2 = 10;int maxVal = MAX(num1, num2);std::cout << "Max value: " << maxVal << std::endl;return 0;
}

在上述代码中,MAX是一个宏函数,预处理器会将MAX(num1, num2)替换为((num1) > (num2)? (num1) : (num2))

4. 三者的区别

  • 作用域和生命周期
    • static修饰的局部变量作用域在函数内,生命周期贯穿整个程序;修饰的全局变量作用域在源文件内,生命周期也是整个程序;静态成员变量和函数属于类,生命周期与程序相同。
    • const修饰的变量作用域取决于其定义位置,常量在其作用域内保持不变,生命周期与其作用域一致。
    • #define定义的宏常量和宏函数作用域从定义处到文件结束,在预处理阶段进行替换,没有实际的作用域和生命周期概念。
  • 类型检查
    • staticconst都有类型,编译器会进行类型检查。
    • #define只是简单的文本替换,没有类型检查,可能会导致一些不易察觉的错误,例如#define ADD(a, b) a + b,如果调用ADD(3, 5) * 2,实际会被替换为3 + 5 * 2,结果与预期不同。
  • 内存分配
    • static修饰的局部变量和全局变量都在全局数据区分配内存;静态成员变量在类的静态存储区分配内存。
    • const修饰的常量如果是基本类型且在编译期可以确定值,可能会被优化到常量存储区,否则在栈上(局部常量)或全局数据区(全局常量)分配内存。
    • #define定义的宏在预处理阶段替换,不占用运行时内存。
  • 可调试性
    • staticconst常量在调试时可以正常显示和跟踪。
    • #define宏在预处理后就不存在了,调试时很难跟踪宏替换后的实际代码。
http://www.dtcms.com/a/339755.html

相关文章:

  • Java:Assert与 Return
  • ZKmall开源商城跨境物流解决方案:让全球配送从复杂到可控的实战之路
  • 深入理解 MySQL 主从同步
  • 【弦乐教程】弦乐家族与音源解析:从乐器到音色的全面认识
  • nodejs使用
  • python matplotlib库如何使用
  • 构造:算法设计中的“魔法工具箱
  • 【C++】C++ 的护身符:解锁 try-catch 异常处理
  • IPD流程执行检查表
  • pnpm 和 npm 差异
  • Spring事务基础:你在入门时踩过的所有坑
  • MoonBit Perals Vol.06: Moonbit 与 LLVM 共舞 (上):编译前端实现
  • 【深度解析】2025年中国GEO优化公司:如何驱动“答案营销”
  • python学习DAY46打卡
  • Vulkan笔记(十)-图形管道的七个配置项
  • 微服务-07.微服务拆分-微服务项目结构说明
  • VulKan笔记(九)-着色器
  • Qt消息队列
  • MySQL深分页性能优化实战:大数据量情况下如何进行优化
  • MySQL 三大日志:redo log、undo log、binlog 详解
  • 面试题储备-MQ篇 1-说说你对RabbitMQ的理解
  • 3D检测笔记:MMDetection3d环境配置
  • 基于单片机智能手环/健康手环/老人健康监测
  • DataSourceAutoConfiguration源码笔记
  • 47 C++ STL模板库16-容器8-关联容器-集合(set)多重集合(multiset)
  • Lec. 2: Pytorch, Resource Accounting 课程笔记
  • 告别手写文档!Spring Boot API 文档终极解决方案:SpringDoc OpenAPI
  • 一文速通Ruby语法
  • GeoTools 读取影像元数据
  • 常见 GC 收集器与适用场景:从吞吐量到亚毫秒停顿的全景指南