值传递和引用传递
值传递
当实参的值被拷贝给形参时,实参和形参是两个独立的变量,我们说实参被值传递或者函数被传值调用。
- 普通形参
形参与实参独立,对形参的改变不会影响实参。
int i = 0;
void change(int z)
{
z = 43; //i的值仍为0
}
change(i);
上述代码执行完毕后i的值仍是0;
- 指针形参
当执行指针拷贝操作时,拷贝的是指针的值指针的值,拷贝之后两个指针是不同的指针。通过指针可以间接修改指针所指向的对象。
int i = 0;
void change(int *p)
{
*p = 43; //i的值为43
p = 0; //只改变指针p的局部拷贝,实参未改变
}
引用传递
将形参绑定到实参,对引用的操作实际上是作用在引用所引的对象上。使用引用传递的优势:
- 使用引用避免拷贝——如果函数无须修改引用形参的值,最好将其声明为常量引用;
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
- 使用引用形参可以返回额外的信息,因修改形参对传入的实参有效。
int i = 0;
void change(int &p)
{
p = 43; //i的值为43
}
const 形参和实参
顶层const & 底层const
顶层const:指针本身是常量,指针所指的对象不是常量。
底层const:指针所指向的对象是常量。
int i = 0;
const int ci = 4; //顶层const,不允许改变ci的值
int *const p1 = &i; //顶层const,不能改变p1值
const int *p2 = &ci; //底层const, 允许修改p2的值
指针或引用形参与const
void reset(int *i)
{
*i = 0; //改变i指向的值
}
void reset(int &k)
{
k = 0; //改变k指向的值
}
形参初始化方式与变量初始化方式一样。
变量初始化方式
int i= 0;
const int* cp = &i; //底层const,cp不能改变i的值
const int &r = i; //底层const, 但是r不能改变i
const int &r2 = 42; //字面量初始化一个常量引用
int *p = cp; //错误,p的类型不是常量指针
int &r3 = r; //错误,r3得类型和r的类型不匹配
int &r4 = 42; //错误,不能用字面量初始化一个非常量引用
形参初始化方式
扫描二维码关注公众号,回复:
188581 查看本文章
int i= 0;
const int ci = i;
string::size_type ctr = 0;
reset(&i); //调用形参类型是int*的reset函数
reset(&ci); //错误,不能用指向const int对象的指针初始化int*
reset(i); //调用形参类型是int&的reset函数
reset(4); //不能把字面量绑定至普通类型上
reset(ctr); //类型不匹配
总结:当函数不对传入的形参做改变时,应将该形参设置为常量引用。将函数不会改变的形参定义为普通引用容易让调用者误会,即该参数可以被修改。且我们不能把const对象、字面量值传递给普通引用形参。例:reset(4); //不能把字面量绑定至普通类型上