const /*/& 在一起要干嘛 ?!
一、关键字Const作用:
1.可以定义const常量,具有不可变性。
例如:const int Max=100; Max++会产生错误;
例如: void f(const int i) { .........} //编译器就会知道i是一个常量,不允许修改;
3.可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!如1.中,如果想修改Max的内容,只需要:const int Max=you want;即可!
4.可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。 还是上面的例子,如果在函数体内修改了i,编译器就会报错;
例如: void f(const int i) { i=10; } //error!
5.为函数重载提供了一个参考;
例如:class A
{
......
void f(int i) {......} //一个函数
void f(int i) const {......} //上一个函数的重载
......
};
6. 可以节省空间,避免不必要的内存分配。const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝。
例如:
#define PI 3.14159 //常量宏
const double Pi=3.14159;
//此时并未将Pi放入RAM中 ......
double i=Pi; //此时为Pi分配内存,以后不再分配!
double I=PI; //编译期间进行宏替换,分配内存
double j=Pi; //没有内存分配
double J=PI; //再进行宏替换,又一次分配内存!
7. 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
二.Const限定符在C/C++中区别:
1.C语言中的常变量的不可以定义数组。因为C中的常变量和变量唯一的区别是不能作为左值,其他性质都和变量一样。eg: 在.C中,有三种修改const常变量值的方式:
int b=20; const int a= 10;
1) int *p=&a; *p=20;
-
2) _asm
{mov dword[ebp-8] 14h}3) *(&b-1)=20;
C语言中可以引用外部const变量声明/定义,会生成一个global符号。链接器在连接的时候,只看g符号。而在其前加上static,就会变为local。除了外部常量,外部变量产生的符号也是g。
2 . C++中的常变量可以作为数组的下标,可以定义数组。常变量是常量。但是在某些情况下,会退化为 变量。
C++中常变量在编译阶段所有出现常量名字的地方会被常量值替换,但不会替换类似&a表达式中的a,当a是const常量时。而C中的常变量在编译阶段并不会被替换。
C++中不可以引用外部文件定义的常量,因为产生的是local符号 ;
因为替换的时候只能在当前文件中替换。如果要能被外部引用到,在变量定义时加上一个extern,就可将其链接属性变为global.
当一个常变量的初始值为外部定义的值时,此时常量就会退换成常变量。因为编译阶段不知道初始值,链接时才知道有这个符号的定义,运行时才会赋值。那么常量的所有汇编也都会变成和变量一样。
三.Const限定符与&.*的结合:
1.const 和一级指针的结合 :当const修饰一个变量名时,并不是意味着这个变量所占的内存是const,而是不能通过这个名字对其修改或泄露常量内存地址或引用。例如:
常见用法:
int a = 10;
const int *p = &a;
int *q = p;
4.const和二级指针的结合,例如:
1)常见错误:
int a = 10;
int *p = &a;
const int **q = &p;
int** -> const int **: const修饰的哪个变量就先改变哪一边 *q<->p这里的*p会泄露常量地址,所以出错!如果,**q<->*p,将一个常量的值放入const修饰的变量中,则不会出错。
2)经过修改之后:
int a = 10;
int *p = &a;
const int * const *q = p;//这里组织*q被非法修改;
3)又如:
int a = 10;
int *p = &a;
int * const *q = &p;//**q<->*p也没有问题;
4)当const和指针结合时,若const右边无指针时,有没有const无区别。因此不能构成重载。
void func(const int a)
{
}
void func(int b)
{
}
5)当对实参的值有影响时,才会构成重载。下面这个就可以构成重载。
void func(const int* a)
{
}
void func(int* b)
{
}
6)类型转换总结:
错误的类型转换:会把常量的地址放在一个普通的指针里面!!
int * - > const int * --> right
const int * -> int * --> error!
int **- > const int ** <相当于> int *& -> const int * --> error!
const int ** -> int ** <相当于> const int *& -> int * --> error!
int* const * -> int ** -->error!
//const跟多级指针结合,必须两边都给修饰!!
5.引用:
引用就是一个指针,无论是什么时候占四个字节。
C++中一个空类占一个字节(不同编译器不一样,有的不可以定义)
struct
{
char a;
char b;
char c;
}data;
//sizeof(data)=3
引用在使用时自动解引用
sizeof(p)=16 (引用了一个数组)
//sizeof(p)=16
如果不好直接写引用,可以在写的时候可以先写成一个函数指针(引用数组名),然后改为引用。
在这个内存地址上写一个四字节的整数10
int p=(int )0x0018ff44
*p=10;
//要想定义一个引用变量,如果右边地址不可取,就弄一个常引用
int const &p=(int )0x0018ff44
*p=10;
下面的错误,是vc的一个bug,编译器检测不出泪,vs可以检测出来
相当于将int**转化为一个const int *,从引用角度来看,p和q是同一块内存,int 和const int *不能是同一块内存。所以错误 !
错误, p是一个const常量,由于*q=p,所以最后一句应改为
int *const*q=&p;
//由于*q<->p,因此给*q赋一个整型常量的地址也就是相当于给p附一个整型常量地址,但是这样会使得整型常量地址泄露,因此修改的办法有两种防止地址泄露被修改:
1)
//让*p为常量,防止它被赋值。
2)
//禁止*q的改变,达到给p赋值的目的
7.C++11中出现了左引用和右引用。
引用占内存,四个字节,&b打印出来就是a的地址,引用地址就是所引用变量的地址,使用引用时,自动解引用。
1)左值引用
左值引用只能绑定左值,不能绑定右值.
如下:
- int x = 1;
- int &y = x; //绑定左值,正确
- int &z = 2; //绑定右值2,编译错误
如:
- //右值绑定到const左值引用
- nt const &i = 28; //正确
- void print(std::string cosnt& s) {}
- print("hello"); //“hello”字符串是临时字符串对象,也是右值
右值引用只能绑定右值,不能绑定左值.使用两个&&表示右值引用.
如:
- int&& i = 8;
- int j = 18;
- int&& k = j; //编译错误
- void fun_reference(int& a)
- {
- std::cout << "左值引用:" << a << std::endl;
- }
- void fun_reference(int&& a)
- {
- std::cout << "右值引用:" << a << std::endl;
- }
- int main()
- {
- int x = 8;
- fun_reference(x); //输出左值引用:8
- fun_reference(18); //输出右值引用:18
- return 0;
- }
[就暂且先总结这么多吧,水平跟见识也有限,还望大家多多批评指正!!]