const
const的出现,把一个变量转换为一个常量,这样就避免了变量赋值在程序中由于过失而被改变,因为const是只读的。
1 定义const
因为常量在定义后不能被修改,所以const对象在定义时必须初始化。
const std::string s = "welcome";//正确
const int i;//错误
2 const对象默认为文件的局部变量
//file_1
int i ;
//file_2
extern int i; //使用file_1中的i
i++; //非const对象在file_2中仍然可以使用
除非特别说明,在全局作用域声明的const变量是定义该对象的文件的局部变量,不能被其他文件访问,只存在于定义它的文件中。
非const变量默认为extern。要使const变量能在其他文件中使用,必须显示地定义为extern const
//file_1
extern const int j = 3;
//file_2
extern const int j;//使用file_1中的j
while(j!=5)
{...}
引用
1 引用只是别名
引用只是它绑定的对象的别名,所有在作用在引用上的操作其实都是作用在该引用绑定的对象上。
引用必须用与该引用同类型的对象初始化,且必须定义时一并初始化
int i = 3,j=5;
int &k = i; //正确
int &k; //错误
int &k = 3; //错误
int &m = i,&n = j;//定义多个引用
int &m = i,n = j;//m是引用,n是int
const引用
const引用是指向const对象的引用
1 const引用的声明及初始化
1 能用同类型对象去初始化,且声明时初始化
const int i = 1024;
const int &j = i;//用同类型对象初始化
int &m = i;//错误,m是非const引用,指向的值可修改,而i是const对象,不可修改,将普通的引用绑定到const对象是不合法的。
2 也能初始化为不同但相关类型*的对象或者右值(只有const引用能这样,非const引用依旧遵循只能用同类型对象去初始化)
int i = 3;
const int &j = 3;//合法
const int &m = &i+j;//合法
绑定到不同类型时;
double i = 3.14;
const int &j = i;
编译器会把代码转换为如下形式的编码:
int temp = i;
const int &j = temp;//仅允许const引用绑定到需要临时变量作为媒介来完全绑定过程的值,因为const引用是只读的。
const形参
1 若函数形参为非引用非const,则既可以给该函数传递const实参也可以传递非const的实参。
int rgcd(int a,int b)
{...}
const int i=3,j =6;
int k = rgcd(3,6);//合法
2 若形参定义为非引用的const类型,则在函数中不可改变实参的局部副本,但由于实参仍然是以副本的形式传递,所以既可以传递const实参,也可以传递非const实参
int fcn(const int i)
{...}
引用形参
引用形参和指针形参的出现,主要为解决复制实参的局限性
不宜复制实参的情况包括:
- 当需要在函数中修改实参的值
- 当需要以大型对象作为实参传递时。对实际应用而言,复制对象所付出的时间和存储空间代价往往过大
- 当没有办法实现对象的复制时
指针形参
形参是指针形参的,传递对象时是复制指针实参。如果函数是将新的指针值赋给形参,主调函数使用的实参指针的值没有改变。
void reset(int *ip)
{
*ip = 0;//使ip指向的对象值为0
ip = 0;//仅改变ip在该函数中的值,实参并未改变
}
int i = 42;
int *p = &i;
cout<<"i:"<<*p<<'\n'; //i:42
reset(p);
cout<<"i:"<<*p<<endl;//i:0
如果要保护指针指向的值,则形参要定义为const对象的指针
void use_ptr(const int *p)
{
//只能读取指针指向的值,而不能改变至指针指向的值
}
既可以用int 也可以用const int 的实参来调用use_ptr函数,但仅能将int *类型的实参传递给reset函数。可以将指向const对象的指针初始化指向非const对象,但是不可以让指向非const对象的指针指向const对象
引用形参
与所有引用一样,引用形参直接关联到其所绑定的对象,而并非这些对象的副本。
使用引用形参返回额外的信息
比如解决函数有不止一个内容需要返回利用const引用避免复制
如果使用引用的唯一目的是避免复制实参,则应将形参定义为const引用类型。更灵活的指向const的引用
//函数形参为非const引用 int incr(int &val) { return val++; } int main() { short v1 = 0; const int v2 = 42; int v3 = incr(v1); //错误 v1不是int v3 = incr(v2); //错误,v2是const v3 = incr(0); //错误,0是常量,不是左值 v3 = incr(v1+v2); //错误,加起来也不是左值 int v4 = incr(v3); //正确,v3是int }
应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活,这样的形参既不能用const对象初始化,也不能用字面值实参或者产生右值的表达式的实参初始化。
传递指向指针的引用
通过实现两个指针的交换,实现交换两个整数的函数void ptrswap(int *&v1, int *&v2) { int *temp = v2; v2 = v1; v1 = temp; }
int *&v1 从右至左理解,只是传进ptrwasp 函数的任一指针的别名
int main() { int i = 10; int j = 20; int *pi = &i ; int *pj = &j ; cout<<"Before ptrswap():\t *pi:"<< *pi<<"\t *pj:"<< *pj<<endl; ptrswap(pi,pj); cout<<"After ptrswap():\t *pi:"<< *pi<<"\t *pj:"<< *pj<<endl; return 0; }
执行结果为:
Before ptrswap(): *pi :10 *pj:20
After ptrswap(): *pi :20 *pj:10
即指针的值被调换了。之前pi指向i,pj指向j,现在pi指向j,pj指向i。