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++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元

C/C++的OpenCV 进行图像梯度提取的几种实现

《C/C++的OpenCV进行图像梯度提取的几种实现》本文主要介绍了C/C++的OpenCV进行图像梯度提取的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录预www.chinasem.cn备知识1. 图像加载与预处理2. Sobel 算子计算 X 和 Y