C++中的const的使用详解

时间:2021-10-25 07:55:36

const的基本使用

const的用法我觉得对于一个以后想着做一个优秀的程序员来说,这是必须熟练掌握的技能。因为网上有好多的文章介绍它的写的非常好,有的我就直接拿过来了~,现在我们来看看他的用法。

const 要求他所修饰的对象为常量,不可被改变,不可被赋值,不可作为左值.

1、函数体内修饰局部变量

例:

?
1
2
3
void func(){
const int a=0;
}

const作为一个类型限定词,和int有相同的地位。

const int a; int const a;

是等价的。于是此处我们一定要清晰的明白,const修饰的对象是谁,是a还是int
const要求他所修饰的对象为常量,不可被改变,不可被赋值,不可作为左值(l-value)。所以很明显它修饰的是a。这是一个很常见的使用方式:

const double pi=3.14;

在程序的后面如果企图对pi再次赋值或者修改就会出错。然后看一个稍微复杂的例子。

const int* p;

因为int* p;和 int *p;是等价的。
所以const int (*p)和int const (*p)是等价的。现在一目了然const 修饰的是谁? 是*p.所以p+=1;是合法的

*p+=1;是非法的因为const修饰了你。

int* const p;那这个什么意思?

看const修饰的是什么? 它修饰的p。但是p是一个int型的指针,所以这个指针的地址没有办法修改。

p+=1; //这就是非法的
*p+=1; //这个是合法的

再看一个更复杂的例子,它是上面二者的综合

const int* const p;说明p自己是常量,且p指向的变量也是常量。
于是

p+=1; //非法
*p+=1; //非法

const 还有一个作用就是用于修饰常量静态字符串。例如:

const char* name=David;

如果没有const,我们可能会在后面有意无意的写name[4]='x'这样的语句,这样会导致对只读内存区域的赋值,然后程序会立刻异常终止。有了 const,这个错误就能在程序被编译的时候就立即检查出来,这就是const的好处。让逻辑错误在编译期被发现。

2、在函数声明时修饰参数
举个例子void * myMemMove(void *dst,constvoid *src,intcount )这是我写的memmove函数的声明,这个函数的意思就是(任意类型)把*src的内容复制给*dst,我们现在很明显的看到*src它只让你复制,你不能修改它的值,所以怕你在以后的函数的定义里出现问题现在在声明里限制你。

3、全局变量
我们的原则依然是,尽可能少的使用全局变量。我们的第二条规则 则是,尽可能多的使用const。如果一个全局变量只在本文件中使用,那么用法和前面所说的函数局部变量没有什么区别。如果它要在多个文件间共享,那么就牵扯到一个存储类型的问题。

有两种方式。

1.使用extern
例如
/* test.h */
extern const double pi;
/* test.c */
const double pi=3.14;

然后其他需要使用pi这个变量的,包含test.h

#include test.h

或者,自己把那句声明复制一遍就好。

这样做的结果是,整个程序链接完后,所有需要使用pi这个变量的共享一个存储区域。

2.使用static,静态外部存储类

/* constant.h */
static const pi=3.14;

需要使用这个变量的*.c文件中,必须包含这个头文件。

前面的static一定不能少。否则链接的时候会报告说该变量被多次定义。这样做的结果是,每个包含了constant.h的*.c文件,都有一份该变量自己的copy,该变量实际上还是被定义了多次,占用了多个存储空间,不过在加了static关键字后,解决了文件间重定义的冲突。坏处是浪费了存储空间,导致链接完后的可执行文件变大。但是通常,这个,小小几字节的变化,不是问题。好处是,你不用关心这个变量是在哪个文件中被初始化的。
其实const我觉得更多是程序员自己限制自己,自己告诉自己后面哪里不能出现错误

举个例子吧。

?
1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
#include<Windows.h>
int main()
{
    int *p;
    const int a = 0;
    p = &a;
    *p = 3;
    printf("a= %d \n", a);
    system("pause");
    return 0;
}

现在看看运行结果

C++中的const的使用详解

现在我要说一个const操作里面比较骚的一些做法,

举个例子我们以前写过的一个类,我们会使用operator[]来返回一个reference的指向,这个一般情况我们都会写一个

const的也会写一个非const的opeartor[].这是我们最常见的一个代码:

?
1
2
3
4
5
6
7
8
T& operator[](int position)
{
 return xxx[position];
}
const T& operator[](int position) const
{
 return xxx[position];
}

这是我们平时写的初级的代码,但是现在当我们要写一个TextBlock内的opeartor[]不单只返回一个referencr了,也可能执行边界检查,日志访问信息,还有什么数据完善性检验等等一大堆繁琐的代码,这个时候当你实现operator[] const和operator[]() const,的时候两份代码大部分都一样,这里伴随的是代码重复,编译时间变长,维护代码膨胀等等头疼的问题. 当然啦,你可以让上述那些繁琐的函数全部封装的别的函数中,然后分别在operator[]()和operator[]()const当中调用但是你还说重复了一些代码比如两次return语句,函数调用.真正该做的是实现operator[]的机能一次并使用它两次。也就是你只需要写一个函数,令另外一个调用这个,这促使我们将常量性转移. 接下来 见证奇迹我们来看看下面这个代码是怎么实现的上述的操作的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class TextBlock
{
public:
 ...
 const char& operator[](std::size_t position) const
 {
 ...
 ...
 ...
 return text[position];
 }
 
 char& operator[](std::size_t position)
 {
 return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
 }
};

来仔细看这个操作;return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
首先把*this强制转换为const TextBlock,再然后调用const的operator[],最后再把const的operator[]的返回值的const常量性取消,然后返回一个非const的值. 这里的调用实在是太妙了,我们可以思考一下,好好想想这里的深意.
但是会有人说,为什么不用const operator[]调用operator[]呢,这样强制两个都可以行的通啊.这样想是错的!

令const版本调用调用no-const版本以避免重复并不是你该做的事情. 记住const所修饰函数的承诺就是我绝对不会修改你,no-const函数可没有这种承诺,所以你让一个const函数去调用一个no-const函数是不现实的. over其实const有很多可以玩的属性,只要我们想到就可以去实现,这里就说这么一个就ok. 接下来我们来瞧瞧另外两个关键字.

 C++中的const的使用详解

const在c/c++中还是会经常出现的,并且如果不理解const会在编程出现的错误而不知所措,无法理解。下面从几个角度简要理解const的内容,应该还是蛮有用的。

const与指针类型

const int*p = NULL; 和int const*p = NULL;是等价的。因为const都在“ * ”的前面,其实是以*为标志的。

?
1
2
3
4
1. int x = 3; const int *p = &x;
 
 
// p = &y;正确 , //*p = 4;错误

指针其实一般是4个字节长度。p的内容是存储0x….,就是其他数据的地址。因此这里的const修饰*p就是说:*p的内容是不可直接被赋值改变的。

而p本身存储的地址是可变的,可以变成其他的0x…..当p指向其他的数据地址时,*p也就随之变成新的数据。

?
1
int x = 3; int *const p = &x; //p = &y是错误的

总结:其实是看这个const是在的前面还是后面,如果在的前面,则表示修饰的是整个“ p ”,而在后面,则表示修饰的是只有p。

显然有:在前面,则表示整个*p是const的,因此p可以指向其他的地址,而*p则是const的,无法改变。同理,int *const p = &x;则表示指针p是固定的,就是说p指针存储的地址是固定的,其内容是const,因此无法修改为其他值(即指向其他地址)。

const与引用

?
1
2
int x = 3; const int &y = x;
//x = 10;正确 //y = 20; 错误

引用前面有const,所以不能通过y来修改x的值。

本人的理解:const int &y就是相当于const int *y1 = &x;然后y = 20就相当于*y1 = 20;这显然时不允许的(就如前面所说的,*p时const,无法直接赋值给*p)。因为引用就相当于给x取了一个别名y,此时y不就是y1指针所指的内容吗?也就是说上面的例子:y = 20;就是相当于 *y1 = 20.

错误的const使用

其他:const int x = 3; int *y = &x; 不能通过编译。因为可能通过*p修改本应该是const的x;
int x = 3; const int *y = &x; 这是可以的,这里的x是可变的,通过由于*y是const的,因此*y就是只能是读取x的值,而不具有写入x的权利。

总结:可以说是只能把一个东西权限缩小,而不能使其原始的权限增大。

const在函数中的应用

主要是防止函数的误操作,对值进行更改

?
1
2
3
4
void fun(const int&a, const int&b)
{
//这里就不能对a或b进行更改,否则会编译出错
}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

原文链接:http://blog.csdn.net/hungryof/article/details/45619905