在说明auto 和 decltype 的用法和区别之前,现补充一点关于const的知识:
一、 const限定符:
在声明一个对象的时候,我们可以使用关键字const修饰,表示这个对象是个常量:
const int a=10;
如果我们做了这样的限定,就意味着以后不可在程序中不能再对a的值进行改变,也就是说:名称为a的这个存储空间内的数据不允许后面的程序添加改变,这也带来了使用const的第一条性质:
常量(const)对象必须在声明的时候初始化。
下面的语句是错误的:
const int a;
a=10 // 错误,const 常量需要设置初始值。
二、const 修饰的对象:
1. 当类修饰类成员: 表示该类成员是常量,不可修改;
2. 当在类中修饰类成员函数:该函数不能修改该类的数据成员,也不能调用其他非const 函数; eg: int fun(int a,int b) const{ /函数体/ };
3. const 函数不能调用非const 函数;非const 函数可以调用const函数。
4. 如果const构成了函数重载,那么const对象只能调用const函数,非const 对象优先调用非const 函数。
5. const 修饰函数返回值,当const 修饰函数返回的指针或者引用时,用const 修饰它可以保证不在函数返回时对其进行更改,像下面这样的代码一样:
class A
{
private:
int i;
public:
A(int a = 0) { i = a; }
const int* r() // (1)
{
return &i;
}
};
A s;
cout << s.r() << endl;
*s.r() = 2; //(2) 编译器会在这一步报错,显示表达式必须是可修改的左值,如果没有(1)处的const,则这一步会将对象s的私有变量i更改为2.
cout << *s.r();
- 在上述代码的(2)处使用语句 : int* t=s.r(); t = 2; 也是行不通的,因为const int 类型的值不能用于初始化int* 类型。
-
const 修饰指针这样的复合类型时,分为顶层const和底层const;以指针为例:
底层const 意味着const修饰的是指针指向的存储空间: const int *p=&a, 意思是不能通过指针p来改变a的值(但是a的值未必是不可改变的);顶层const意味着const 修饰的是指针本身: int * const p=&a, 意思是**不能改变p的指向,即p只能指向a,**对能不能改变a的值不做要求。
-
const 类型限定的指针不能赋值给非const限定的指针,一般情况下,非const限定的指针允许赋值给const的指针;之所以要加一个一般情况,是因为,在类似下面的代码中,非const限定的指针是不能赋值给const的指针,会引起一个error: “初始化”: 无法从“int * *”转换为“const int **” ;
int *p1;
const int n=5;
const int * pp2 = &p1; (1) //error: “初始化”: 无法从“int * ”转换为“const int ”
*pp2 = &n; (2)
*p1 = 10; (3)
之所以不允许这种赋值,是因为这样的写法可以使用非const 的指针p1在(3)处合情合理的改变常量n 的值,因此,C++禁止在这种情况下将非const限定的指针是不能赋值给const的指针。
总之,当对底层const 对象进行赋值时,必须保证双方具有相同的底层属性。 -
一般情况下,声明为const的对象存储在常量区,