C++略识 之关键字const

2024-08-24 09:18
文章标签 c++ 关键字 const 略识

本文主要是介绍C++略识 之关键字const,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、const修饰的变量必须进行初始化

-->一般数据类型const常量初始化

const int i = 10; //合法

const int j; //非法,导致编译出错

-->指针const常量初始化

int *p = new int();

const int *p  =q; //等价于 int const *p = q;

-->引用const常量初始化

int *p = new int();

const int *p  =q; //等价于 int const *p = q;

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

2、const限定符声明的的变量具有只读属性

const int i = 10;

int j = 0;

// to do ...

i = j; //非法,导致编译出错

j = i; //合法

3、const相比较于define,可以避免不必要的内存分配

#defineSTRING "abcdefghijklmn\n" 

  const charstring[]="abcdefghijklm\n"; 

  ... 

 printf(STRING); //为STRING分配了第一次内存 

 printf(string); //为string一次性分配了内存,以后不再分配 

  ... 

 printf(STRING); //为STRING分配了第二次内存 

 printf(string); 

  ...

由于const定义常量从汇编的角度来看,只是给出了对应的内存地址, 而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。

4、是不是const的常量值一定不可以被修改呢?

非也!!!

const int i=0; 

int *p=(int*)&i; 

p=100;

通过强制类型转换,将地址赋给变量,再作修改即可以改变const常量值。说明了申明为常量的数据也可能被改变。

我这里补充的是不要对const 的滥用。强制绕过const 检查可能会引起运行错误。

把const int i=0 声明在函数内,能够达到你的目的;把const int i=0 声明为全局变量,虽然仍然能够用强制转换绕过编译器检查,但会引起运行错误。
可参考下例:

const int j=50;  
void main()  
{  const int i=0;  int *p=(int*)&i;  *p=100;   int *p2=(int *)&j;  *p2=200;  // runtime error  cout << &i << &j;  system("pause");  
}

5、必须分清楚是数值常量还是指针常量

int j=0; 

const int i=0; //i是常量,i的值不会被修改 

const int *p1=&i; //指针p1所指内容是常量,可以不初始化 

int * const p2=&j;//指针p2是常量,所指内容可修改 

const int * const p3=&i; //指针p3是常量,所指内容也是常量 

p1=&j; //不合法 左操作数包含“int *”类型 

*p2=100; //不合法  右操作数包含“int *const ”类型

[注意]:指向常量的指针并不能保证所指向的值不被改变。比如:

const int i=10;  
void main()  
{  const int j=20;  int k = 30;  const int * p1=&i;  const int * p2 = &j;  const int * p3 = &k;  // i=80; fail  // j= 20; fail  // *p3 = 50; fail  // 以上三种均未逃过编译器检查  k=80;   // succeed 逃过了编译器检查。 *p3 不行,但直接改k 允许。  system("pause");  
}

6、const修饰类的数据成员

class A  
{  const int size;  //to do…    
}

[注意]:const修饰的数据成员只在某个对象的生存周期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const修饰的数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。比如:

class A  
{  const int size = 100; //错误  int array[size]; //错误,未知的size  
}  

const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现。比如:

class A  
{  //to do…  enum { size1=100, size2 = 200 };  int array1[size1];  int array2[size2];    
}  

[注意]:枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。

7、const在函数声明中的应用

在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数,比如:

void fun1(const A *a );    
const A fun2( );
void fun3( ) const; // fun3( )为某个类的成员函数

[注意]:调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,比如:

void fun1(const A *a); //不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容
void fun2(const A &a); //不能对传递进来的引用对象进行改变,保护了原对象的属性<a target=_blank name="OLE_LINK2" style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></a>
<span style="font-family: Arial, Helvetica, sans-serif;  background-color: rgb(255, 255, 255);"><strong><span style="color: red;">[注意</span><span style="color: red;">]</span></strong></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">:参数const通常用于参数为指针或引用的情况,且只能修饰输入参数;若输入参数采用“值传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">保护,所以不用const修饰。</span>

[小结]

--->对于非内部数据类型的输入参数,因该将“值传递”的方式改为“const引用传递”,目的是为了提高效率。例如,将void Func(A a)改为void Func(const A &a)。

--->对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x)不应该改为void Func(const int&x)。






这篇关于C++略识 之关键字const的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1102069

相关文章

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python批量替换多个Word文档的多个关键字的方法

《Python批量替换多个Word文档的多个关键字的方法》有时,我们手头上有多个Excel或者Word文件,但是领导突然要求对某几个术语进行批量的修改,你是不是有要崩溃的感觉,所以本文给大家介绍了Py... 目录工具准备先梳理一下思路神奇代码来啦!代码详解激动人心的测试结语嘿,各位小伙伴们,大家好!有没有想

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

Java中的volatile关键字多方面解析

《Java中的volatile关键字多方面解析》volatile用于保证多线程变量可见性与禁止重排序,适用于状态标志、单例模式等场景,但不保证原子性,相较synchronized更轻量,但需谨慎使用以... 目录1. volatile的作用1.1 保证可见性1.2 禁止指令重排序2. volatile的使用