欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[C++] const限定符

程序员文章站 2022-07-09 21:47:37
...

在定义变量时,如果希望该变量是一个只读的常量,则在变量前加const限定符即可。

1.用于基本类型

对于基本类型变量,定义只读常量有两种方式:#define预处理器编译指令和const限定符,前者是C中的语法,后者是C++中特有。

#define和const的区别

#define#include一样,是一个预处理器编译指令,如:

#define SIZE 21

该指令告诉预处理器,在程序中查找SIZE,并将所有的SIZE替换成21。
因此,#define工作方式和文本处理器中的全局搜索并替换命令相似。

在C++中,可以使用const来创建符号常量:

const int SIZE = 20;
//或者
#define SIZE 20

然而,如果有些头文件需要在C和C++中都可用的话,那么必须使用#define

应在变量声明时就对const进行初始化,否则将编译失败:

const int s;//s未提供值,因此编译器将提供一个不确定值
s = 20; //s 已经被编译器赋值,因此将失败

2.用于指针

有两种方式可以将const用于指针,且这两种方式之间有微妙的变化:

  • 1.使用const让指针指向一个常量对象,防止该指针修改所指向的值。
  • 2.使用const让指针成为一个常量指针,防止指针改变指向位置。

先来看第一种方式:

int i = 24;
const int* p1 = &i;
//*p1 = 12;//NOT ALLOWED
i = 30;//OK

这里表示,指针p1指向一个const int类型的数据,对于p来说,*p的值为const int,因此,不能通过p1修改值。

这种方式并不意味着p1指向的值实际上就是一个常量,而是对于p1而言,这个值是一个常量。

在来看第二种方式:

int i = 24;
int j = 50;
int * const p2 = &i;
// p2 = &j;//NOT ALLOWED
*p2 = 29;//OK ,i = 29

这里表示,指针cosnt p2指向一个int类型的数据,因此,p2再不能改变它的指向位置,但是其指向位置的值依然可以改变。

其他性质

  • 1.常规变量的地址可以赋给指向const的指针:
double score = 23;
const double * ps = &score;
  • 2.const变量的地址可以赋给指向const的指针:
const double score = 23;
const double * ps = &score;
  • 3.const变量的地址不可以赋给常规指针:
const double score = 23;
// double * ps = &score;//NOT ALLOWED

score被const限定,说明不能修改它的值,如果将score地址赋给指针ps,则可以使用ps来修改score,这将使得const无意义。

所以,当char 指针指向字面量值时,一定是const char*而不是char*:

const char * p = "Hello world";

3.用于数组名

在数组作为参数的函数中,可以使用const保护数组,避免数组被修改,比如如下示例:

#include <iostream>
using namespace std;

int fill_arr(double arr[],int limit);
void show_arr(const double arr[],int n); 
void revalue_arr(double arr[],double r, int n); 
int main()
{
        double arr[5];
        int length = fill_arr(arr,5);
        show_arr(arr,length);
        revalue_arr(arr,2.2,length);
        show_arr(arr,length);
        return 0;
}

void revalue_arr(double arr[],double r,int n)
{
        for(int i = 0;i<n;i++)
        {
                arr[i] *= r;
        }
}

void show_arr(const double arr[],int n)
{
        for(int i=0;i < n;i++)
        {
                cout << "arr["<<i << "]:" << arr[i] << endl;
        }    
}

int fill_arr(double arr[],int limit)
{
        int i = 0;
        double temp;
        for(; i < limit;i++)
        {
                cout << "Enter value #" << (i+1) << endl;
                cin >> temp;
                if(!cin)
                {
                        cin.clear();
                        while(cin.get() != '\n')
                        {
                                continue;
                        }
                        cout << "Bad input;break";
                        break;
                }else if (temp < 0)
                {
                        break;
                }
                arr[i] = temp;
        }
        return i;
}

在这个示例中,三个函数都有一个参数是数组,因为数组作为参数时,传递的实际上是它的地址,因此,在fill_arr()revalue_arr()函数中,对形参修改,实际上修改的就是原始数组,而在show_arr()函数中,避免数组被修改,将形参用const修饰,而常规变量赋给const变量是允许的。

由于数组和指针在大多数情况下是一样的,因此,在数组和指针用于形参时,因尽可能地将他们声明为const,一是可以避免数据的无意识修改,二是使用const,函数可以处理const和非const数据,否则只能使用非const数据。

4.用于引用

将const用于引用时,说明该引用是一个常量引用,如果将引用作为函数参数时,应尽可能地使用const限定,这是因为,如果函数实参和引用形参不匹配时,只有当引用参数为const的情况下,C++会在必要时生成临时变量。一般有如下两种情况:

  • 1.实参类型正确,但不是左值;
  • 2.实参类型不正确,但可以转换为正确的类型。

如:

#include <iostream>
int add( int& i,  int& j);
int main()
{
	using namespace std;

	int i = 45;
	int j = 200;
	int sum = add(i,j);
	cout << "sum=" << sum << endl;
	long h = 12;
	long k = 400;
	//sum = add(h, k);//无法用long类型的值初始化int&类型的引用
    //sum = add(3,6);//非常量引用的初始值必须为左值
	system("pause");
	return 0;
}
int add(int& i, int& j) {
	return i + j;
}

在上例中,add()函数中使用long类型的数据将编译失败,这是因为,无法用long类型的值初始化int&类型的引用。同时无法使用add(3,6),但是如果将函数引用参数声明为const:

int add(const int& i,const int& j);

则以上两种情况皆可以编译。由于const的声明,当发现实参和引用参数不匹配,编译器会生成一个临时变量,然后让引用参数i,j指向这些临时变量,这些临时变量只会在函数运行期间存在。

将引用参数声明为const引用的理由有三:

  • 1.使用const可以避免无意的修改数据;
  • 2.使用const可以使函数能够处理const类型和非const类型数据,否则只能接受非const数据;
  • 3.使用const引用可以使函数能够正确生成并使用临时变量。
相关标签: const