首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐
2025年7月14日 星期一 2:04am

C/C++中const关键字用法总结

  • 25-02-17 10:01
  • 3620
  • 6436
blog.csdn.net

C++基础专栏:http://t.csdnimg.cn/4FdOH

目录

1.引言

2.修饰变量

2.1.修饰普通变量

2.2.修饰指针

2.3.修饰对象

3.修饰函数形参

4.修饰函数返回值

5.修饰类成员函数

6.const与constexpr区别

7.总结


1.引言

        在面试的过程,面试官经常都会问到const关键字有哪些用法?在C/C++中各有些什么作用?今天就在这里我们好好的总结一下const的全方位用法。

2.修饰变量

2.1.修饰普通变量

        在普通变量前面加上const,表示该变量是常量,不能随便更改值的变量。const 类型的变量必须在定义时进行初始化,之后不能对const型的变量赋值。示例如下:

  1. 在变量定义前加关键字const,修饰该变量为常量,不可修改
  2. const int year= 12;
  3. const char p = 'f';

注意:在函数内部定义的const局部变量和全局定义的const变量还是有很大的不同的?函数内部定义的局部const变量存放在栈区中,会分配内存(也就是说可以通过地址间接修改变量的值), 如:

  1. void func()
  2. {
  3. const int a = 10;
  4. //a += 1; //编译错误,常量是不能修改的
  5. int* p = &a;
  6. *p = 20; //a = 20, 通过指针间接是可以修改a的值的
  7. }

全局const变量存放在只读数据段(不能通过地址修改,会发生写入错误), 默认为外部联编,可以给其他源文件使用(需要用extern关键字修饰)。如:

  1. const int a = 10;
  2. //const int b = a; //不能用全局变量全局初始化const变量,编译不通过,表达式必须含有常量值
  3. void func()
  4. {
  5. int* p = &a;
  6. *p = 20;//编译通过,但运行时会发生写入错误
  7. }

如果是在C++类中定义的const成员变量,那么必须在初始化列表中赋值,如:

  1. //类定义
  2. class CBase
  3. {
  4. public:
  5. explicit CBase();
  6. private:
  7. const int m_a;
  8. };
  9. //类构造函数
  10. CBase::CBase()
  11. : m_a(100)
  12. {
  13. //m_a = 200; //在这里赋初值会出现编译错误,因为这里不是m_a不是赋初值的地方
  14. }

2.2.修饰指针

const修饰指针有几种情况:

① const修饰指针 --- 常量指针

语法:const 数据类型 * 变量名;如:const int* p;

② const修饰常量 --- 指针常量

语法:数据类型 * const 变量名;如:int* cont  p;

③ const即修饰指针,又修饰常量

语法:const 数据类型 * const 变量名;如:const int* const p;

综合示例如下:

  1. int func() {
  2. int a = 10;
  3. int b = 10;
  4. //1)常量指针:const修饰的是指针,指针指向可以改,指针指向的值不可以更改
  5. const int * p1 = &a;
  6. p1 = &b; //正确
  7. //*p1 = 100; 报错
  8. //2)指针常量:const修饰的是常量,指针指向不可以改,指针指向的值可以更改
  9. int * const p2 = &a;
  10. //p2 = &b; //错误
  11. *p2 = 100; //正确
  12. //3)const既修饰指针又修饰常量
  13. const int * const p3 = &a;
  14. //p3 = &b; //错误
  15. //*p3 = 100; //错误
  16. return 0;
  17. }

技巧:看const右侧紧跟着的是指针还是常量, 是指针就是常量指针,是常量就是指针常量

2.3.修饰对象

        const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
        const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。

        示例如下:

  1. class CMyTest
  2. {
  3. public:
  4. CMyTest() : m_a2(10),m_b2(20) {}
  5. void func1(){
  6. m_b1 = 10; //OK
  7. //m_b2 = 30; //ERROR: m_b2是常量不能修改
  8. m_a3 = 40; //OK
  9. }
  10. void func2() const{
  11. //m_b1 = 10; //ERROR: const成员函数不能修改非const成员变量
  12. //m_b2 = 60; //ERROR: m_b2是常量不能修改
  13. m_a3 = 80; //OK
  14. }
  15. public:
  16. int m_a1;
  17. const int m_a2;
  18. mutable int m_a3;
  19. private:
  20. int m_b1;
  21. const int m_b2;
  22. mutable int m_b3;
  23. };
  24. int main()
  25. {
  26. const CMyTest test;
  27. //test.m_a1 = 1000; //ERROR : 编译错误,常对象不能非const成员变量
  28. //test.m_a2 = 2000; ; //ERROR : 编译错误,常对象不能修改const成员变量
  29. test.m_a3 = 3000; ; //OK,常对象能修改mutable成员变量
  30. return 0;
  31. }

        

3.修饰函数形参

在函数参数前面加上const,表示在函数内部不能修改该参数的值,用const来防止误操作。如:

  1. struct student {int num};
  2. void func(const student &stu){
  3. stu.num = 56; //这句就错误了,不能修改stu中的内容
  4. }
  5. student abc;
  6. abc.num = 100;
  7. func(abc);
  8. std::cout << abc.num << std::endl; //100

4.修饰函数返回值

返回基本数据类型的常量值:当函数返回基本数据类型(如 int、float 等)时,使用 const 修饰返回值通常没有太大意义。因为基本类型的返回值通常是按值返回,即返回的是一个副本。修改这个副本并不会影响原始值。如:

  1. const int getValue() {
  2. return 11000;
  3. }

返回对象或复合类型的常量引用:当函数返回对象或复合类型(如自定义类、结构体等)时,使用 const 修饰返回值可以防止返回的对象或复合类型被修改。这是一种常见且有用的做法,特别是在返回类的成员变量时。如:

  1. const MyClass& getClass() const {
  2. return myObject;
  3. }

getClass 函数返回 MyClass 类型对象的常量引用。这意味着调用者可以读取返回的对象,但不能修改它。这种做法既保证了数据的安全性,又避免了不必要的复制。

  1. class MyClass {
  2. private:
  3. int value;
  4. public:
  5. const int& getValue() const {
  6. return value;
  7. }
  8. };
  9. // 在使用时
  10. MyClass obj;
  11. int a = obj.getValue(); // a 不是 const
  12. // obj.getValue() = 10; // 错误,不能通过 const 引用修改值

getValue 方法返回 value 成员的常量引用,这样就保护了内部数据不被外部修改。

5.修饰类成员函数

        成员函数后加const后我们称为这个函数为常函数;const成员函数,能够访问所有成员变量,但是在函数体内不能直接修改变量的值(包括普通成员变量),如果需要在函数体内修改普通成员变量的值,需要在变量定义的前面添加mutable关键字,或者通过地址间接修改。

        注意:const成员函数只能被该类的const对象访问。 

示例如下:

  1. class CMyTest
  2. {
  3. public:
  4. void func() const{
  5. //a = 40; //没有加mutable修饰的变量在const成员函数内不能直接修改
  6. //间接修改a的值
  7. int* p = const_cast<int*>(a);
  8. *p = 50;
  9. //用mutable修饰的变量直接通过
  10. c = 60;
  11. }
  12. private:
  13. int a = 10;
  14. const int b = 20;
  15. mutable int c = 30;
  16. };

6.const与constexpr区别

constexpr 和 const 都是 C++ 中用于声明常量的关键字,但它们在使用上有一些重要的区别:

const

  • const 用于声明一个常量,表示变量的值不可修改。
  • const 可以用于各种类型的变量,包括基本数据类型、对象、指针等。
  • const 变量的值可以在运行时确定。这意味着它可以被初始化为在编译时未知的值,比如函数返回值或者用户输入。
  • const 更加通用,适用于任何需要防止修改的场景。

constexpr

  • constexpr 用于声明表达式为编译时常量,意味着它的值必须在编译时就已知。
  • constexpr 常量可以用在需要编译时常量表达式的上下文中,如数组大小、整数模板参数等。
  • constexpr 函数能在编译时对其输入进行计算,只要所有输入也都是编译时已知的常量。
  • 使用 constexpr 声明的变量或函数表示你希望编译器验证它们能够在编译时求值。
  • constexpr 要求其初始化表达式必须是一个编译时常量表达式。

主要区别

  • 编译时 vs. 运行时:constexpr 确保变量或函数的值能在编译时被确定,而 const 变量的值可以在运行时确定。
  • 使用场景:constexpr 适用于需要在编译时进行计算的场景,比如作为模板参数或数组大小。const 更适用于程序运行中不需要修改的值。

示例如下:

  1. //使用const
  2. const int max_size = getSizeFromUser(); // 运行时获取大小
  3. const double pi = 3.14159;
  4. //使用constexpr
  5. constexpr int max_array_size = 100; // 编译时已知的数组大小
  6. constexpr double computeArea(double radius) {
  7. return 3.14159 * radius * radius; // 编译时计算面积的函数
  8. }

7.总结

使用const还有很多好处:

1) 类型安全:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。

2) 可以节省空间,避免不必要的内存分配: const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象宏一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而宏定义的常量在内存中有若干个拷贝。

3) 优化性能:对于基本数据类型,const对象可能会被编译器优化,因为它们的值在程序的执行过程中不会改变。const方法和constexpr函数可以在编译时进行计算和优化,这可以提高程序的运行效率。

4) 增加代码的可维护性:通过将某些变量或方法标记为const,你可以更容易地重构和修改代码,同时保持对原始设计意图的忠实。const正确性(const-correctness)是一种良好的编程实践,它有助于减少错误并增加代码的稳定性。

5) 为函数重载提供了一个参考:const修饰的函数可以看作是对同名函数的重载。如:

  1. clas MyTest
  2. {
  3. public:
  4. void func(int a, int b);
  5. void func(int a, int b) const;
  6. };

6) 接口设计:在设计类和函数接口时,使用const可以明确哪些操作是安全的,哪些操作可能会修改对象状态。这对于库的设计尤其重要,因为它允许库的使用者更加清晰地理解如何与库进行交互。

7) 保护数据:在多线程环境中,将数据声明为const可以确保它不会被多个线程同时修改,从而避免数据竞争和未定义行为。当然,在多线程环境中仅仅使用const是不够的,但它是一个有用的工具。

8) 兼容性和转换:const对象可以安全地转换为非const对象(在不需要修改对象的情况下),这提供了更大的灵活性。

参考:

const (C++) | Microsoft Learn

注:本文转载自blog.csdn.net的流星雨爱编程的文章"https://blog.csdn.net/haokan123456789/article/details/137397258"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top