C++:const形参 vs 非const形参
1、非const非引用形参:普通的函数形参
以实参副本初始化形参,会改变实参的值;
因为非const非引用形参不会改变实参的值,
因此对实参添加const和不添加const都是一个结果。
#include <iostream>
#include <stdio.h>
using namespace std;
//非const非引用形参可由const或非const实参初始化
int use_ptr1(int val)//非const非引用形参
{
return ++val; //可以修改
}
int main()
{
int v1 = 1; //非const实参初始化
cout << "v1初值: "<<v1 << endl;
use_ptr1(v1); //不改变形参的值
cout << "v1加1操作后: "<<v1 << endl;
const int v2 = 2;//const实参初始化
cout << "v2初值: "<<v2 << endl;
use_ptr1(v2); //不改变形参的值
cout << "v2加1操作后: "<<v2 << endl;
getchar();
return 0;
}
2、const非引用形参:防止修改从实参传递的形参值,故只能使用形参,不能修改形参;
因为const非引用形参不会改变实参的值,
因此对实参添加const、不添加const都是一个结果。
#include <iostream>
#include <stdio.h>
using namespace std;
//const非引用形参可由const或非const实参初始化
int use_ptr2(const int val) //const非引用形参
{
//return ++val; //修改了val的值,错误
return val; //不可修改
}
int main()
{
int v1 = 1; //非const实参初始化
use_ptr2(v1);
cout <<"v1: "<< v1 << endl;
const int v2 = 2;//const实参初始化
use_ptr2(v2);
cout <<"v2: "<< v2 << endl;
getchar();
return 0;
}
结论:
①非const非引用形参和const非引用形参均可由const或非const实参初始化
②非引用形参:是“实参”的一个拷贝副本,修改“形参”不影响“实参”
③const非引用形参,可以拿来使用,但是不能修改形参的值。
3、非const引用形参:直接关联到绑定对象,对“形参”的修改就是对“实参”的修改
①当需要在函数中修改实参的值;
②当需要以大型对象作为实参传递时。对实际的应用而言,复制所付出的时间在位空间代价太大;
③当没有办法实现对象复制
对于上述几情况,有效解决方法是将形参定义为引用类型。
因为非const引用形参可以改变实参的值,因此实参也必须是非const的;否则报错;
#include <iostream>
#include <stdio.h>
using namespace std;
//非const引用形参:直接关联到绑定对象,对“形参”的修改就是对“实参”的修改
int use_ptr5(int &val) //非const引用形参
{ //只能与完全同类型的非const对象关联
return ++val; //不允许传递右值或需要类型转换的对象
}
int main()
{
int v1 = 1; //非const实参初始化
const int v2 = 2;//const实参初始化
short v3=3; //不同类型的初始化
cout <<"v1初值: "<< v1 << endl;
use_ptr5(v1);
//use_ptr5(v2); //error:不能使用const对象指初始化非const引用形参
//use_ptr5(v3); //error;不能使用不同类型的对象来初始化形参
//use_ptr5(0); //error:不能使用右值来初始化
//use_ptr5(v1+v2); //error: 不能使用右值来初始化
cout <<"v1加1操作: "<< v1 << endl;
getchar();
return 0;
}
4、const引用形参:
可以由非const或const实参初始化,
也可以传递右值或需要类型转换的对象,
但是const引用形参值不可修改;
因为const引用形参的值不改变,因此对实参的值没有影响,实参有无const结果相同;
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
using namespace std;
int use_ptr6(const int &val) //const引用形参
{ //可以由非const或const对象初始化
return val; //也可以传递右值或需要类型转换的对象
//return ++val; //不可修改
}
int main()
{
int v1 = 1; //非const实参初始化
const int v2 = 2;//const实参初始化
short v3=3;
use_ptr6(v1);
use_ptr6(v2);
use_ptr6(v3); //OK:类型转换
use_ptr6(0); //OK:右值
use_ptr6(v1+v2); //OK:右值
getchar();
return 0;
}
5、总结
①非const非引用形参和const非引用形参均可由const或非const实参初始化;
②非const引用形参没有const限定符,实参必须是非const类型;
③const引用形参均可由const或非const实参初始化;
原因:
在非引用形参中改变不了实参的值,故实参有无const结果一样;
引用形参可以改变实参的值,故非const引用形参没有const限定符,实参必须是非const类型;而const引用形参不改变实参的值。
【注】:
将不需要修改的引用形参定义为const引用;
因为非const引用形参在使用时不太灵活,不能用字面值或产生右值的表达式实参来初始化。
因此少用非const引用类形参,多余const引用形参。
6、程序:
#include <stdlib.h>
#include <iostream>
using namespace std;
//非引用形参:是“实参”的一个拷贝副本,修改“形参”不影响“实参”
//const常量:值不可修改
//非引用非const形参和非引用const形参均可由const或非const实参初始化
int use_ptr1(int val)//非引用非const形参
{
return ++val; //可以修改
}
int use_ptr2(const int val) //非引用const形参
{
return val; //不可修改
}
//指针形参
int use_ptr3(int *s1) //指针形参指向非const对象
{ //只能由指向非const对象的实参指针初始化
return ++(*s1); //可以修改
}
int use_ptr4(const int *s2) //“指向const对象的指针”作为形参
{ //可以由“指向const和非const对象的实参指 //针”初始化
return *s2; //不可修改
}
/*********************************/
//引用形参”:直接关联到绑定对象,对“形参”的修改就是对“实参”的修改
int use_ptr5(int &val) //非const引用形参
{ //只能与完全同类型的非const对象关联
return ++val; //不允许传递右值或需要类型转换的对象
}
int use_ptr6(const int &val) //const引用形参
{ //可以由非const或const对象初始化
return val; //也可以传递右值或需要类型转换的对象
}
//传递指针的引用
void ptrswap1(int *&s1,int *&s2) //指向非const对象的指针的引用
{
//形参定义的理解:int *&a->a是一个引用,与指向int型对象的指针相关联。
//也就是说,
//a是传递进函数swap的任意指针的别名
//使用“指向非const对象的指针”初始化
int *temp = s2;
s2 = s1;
s1 = temp;
}
void ptrswap2(const int *&s1,const int *&s2) //“指向const对象的指
//针”的引用
{
//形参定义的理解:const int *&a->a是一个引用,与指向int型const对象的
//指针相关联。
//使用指向const对象的指针初始化
const int *temp = s2;
s2 = s1;
s1 = temp;
}
/*********************************/
int main()
{
int v1 = 1;
const int v2 = 2;
short v3 = 3;
cout << v1 << " " << v2 << endl;
use_ptr1(v1);
use_ptr1(v2);
cout << v1 << " " << v2 << endl;
use_ptr2(v1);
use_ptr2(v2);
cout << v1 << " " << v2 << endl;
use_ptr3(&v1);
//use_ptr3(&v2); //error:不能使用指向const对象的指针来初始化指向
//非const对象的指针
cout << v1 << " " << v2 << endl;
use_ptr4(&v1);
use_ptr4(&v2);
cout << v1 << " " << v2 << endl;
use_ptr5(v1);
//use_ptr5(v2); //error:不能使用const对象指初始化非const引用形参
//use_ptr5(v3); //error;不能使用不同类型的对象来初始化形参
//use_ptr5(0); //error:不能使用右值来初始化
//use_ptr5(v1+v2); //error: 不能使用右值来初始化
use_ptr6(v1);
use_ptr6(v2);
use_ptr6(v3); //OK:类型转换
use_ptr6(0); //OK:右值
use_ptr6(v1+v2); //OK:右值
int a = 1, b = 2;
int *p1 = &a;
int *p2 = &b;
const int *p3 = &a;
const int *p4 = &b;
ptrswap1(p1, p2);
//ptrswap1(p3, p4); //error:指向const对象的指针
cout << *p1 << " " << *p2 << endl;
//ptrswap2(p1, p2); //error:指向非const对象的指针
ptrswap2(p3, p4);
cout << *p1 << " " << *p2 << endl;
system("pause");
return 0;
}