引用作为函数参数

本文深入解析C++中的引用概念,包括其定义、初始化规则及如何用作函数参数以实现值传递与引用传递的区别。并通过具体示例展示了引用作为函数参数的应用场景。
         引用是一个变量的别名,除用&取代*外,定义引用的方法与定义指针类似。例如: 
   double num1 = 3.14;
   double &num2 = num1; // num是num2的引用 
   定义num2为num1的引用,它并没有复制num1,而只是num1的别名。也就是说,它们是相同的变量。例如,如果执行下面的语句: 
   num1 = 0.16; 
   则num1和num2 的值均为0.16。
   不同于变量的定义:可以先定义,后初始化。正如上面看到的:引用必须在定义时初始化。例如,下面的定义是错误的: 
   double &num3; // 非法:引用没有初始化
   num3 = num1; 
   引用可用常量来初始化,此时,常量会被复制,引用与其复制值保持一致: 
   int &n = 1; // n 取1的复制值 
   为什么用常量初始化引用时要被复制,我们看下面的例子: 
   int &x = 1;
   ++x;
   int y = x + 1; 
   第一行的1和第三行的1可能占用相同的存储单元(大多数编译器将两个1分配在内存中相同的地方),虽然我们期望y的值为3,但它的结果可能是4,这是由于第二行的++x运算后,常量1的值变成了2。如果我们使x取1的复制值,可保证x的改变不会影响到常量的值。
   其实,引用作为另一个变量的别名用处不是很大,除非变量名很长。引用最重要的用处是作函数的参数。我们知道,函数参数传递有值传递和引用传递两种方式。用引用作为函数,是引用传递方式。为了比较值传递和引用传递的区别,我们仍然以交换两个变量值的函数作为例子: 
引用作为函数参数 - col1 - 求大offer 例5-14 
1 void Swap1 (int x, int y) //值传递
{
  int temp = x;
  x = y;
  y = temp;

2 void Swap2 (int *x, int *y) //引用传递(指针)
{
  int temp = *x; *x = *y;
  *y = temp;
}
3 void Swap3 (int &x, int &y) //引用传递
{
  int temp = x;
  x = y;
  y = temp;

  在上面的三个函数中,虽然Swap1交换了x和y,但并不影响传入该函数的实参,因为实参传给形参时被复制,实参和形参分别占用不同的存储单元。
   Swap2使用指针作为参数克服了Swap1的问题,当实参传给形参时,指针本身被复制,而函数中交换的是指针指向的内容。当Swap2返回后,两个实参可以达到交换的目的。
  Swap3通过使用引用参数克服了Swap1的问题,形参是对应实参的别名,当形参交换以后,实参也就交换了。
下面的main函数说明调用三个函数时的区别: 
引用作为函数参数 - col1 - 求大offer 例5-15 
void main (void)
{
  int i = 10, j = 20;
  Swap1(i, j);
  cout << i << ", " << j << '\n';
  Swap2(&i, &j);
  cout << i << ", " << j << '\n';
  Swap3(i, j);
  cout << i << ", " << j << '\n';

   main函数运行结果如下:
   10, 20
   20, 10
   10, 20
   我们看到函数Swap3与Swap2的效果一样,都达到了交换的目的,但Swap3更直观,调用它的方法与调用Swap1的方法是一样的。但是,引用作为函数参数,调用时可能会出现歧义,例如: 
   void fn(int s)
   {
    …
   } 
   void fn(int& t)
   {
    …
   } 
   void main()
   {
    int a=5;
    fn(a); //匹配哪一个函数?
   }
   当以引用方式传递函数参数时,我们常使用const关键字。例如: 
   void f1(const int i) {
    i++; // 非法,编译错误
   } 
   这可以避免在函数中修改了不该修改的参数,有助于提高程序的可靠性
<think>我们参考了上述引用资料,其中引用[2]和引用[4]提供了函数重载的规则和示例,引用[5]则介绍了引用的概念和特性。用户特别关注使用引用作为函数参数进行重载的方法和示例。 根据引用[4]所述,函数重载的条件包括: 1. 同一作用域 2. 相同函数名 3. 形参列表不同(参数个数、类型、类型次序不同) 当使用引用作为参数时,我们可以通过引用不同类型的变量(如常量引用、非常量引用)或引用不同顺序的组合来实现重载。 以下是一些使用引用作为函数参数进行重载的示例: 1. **通过引用不同类型的变量实现重载**: ```cpp void print(int &a) { cout << "int reference: " << a << endl; } void print(const int &a) { cout << "const int reference: " << a << endl; } ``` 2. **通过引用不同类型(如int和double)实现重载**: ```cpp void print(int &a) { cout << "int reference: " << a << endl; } void print(double &a) { cout << "double reference: " << a << endl; } ``` 3. **通过引用不同顺序的参数类型实现重载**: ```cpp void print(int &a, double &b) { cout << "int, double: " << a << ", " << b << endl; } void print(double &a, int &b) { cout << "double, int: " << a << ", " << b << endl; } ``` 注意点: - 当传递字面值常量时,只能调用常量引用版本,因为字面值常量不能绑定到非常量引用。 - 如果两个重载函数仅在引用是否为常量上有区别,则传递非常量变量时会优先选择非常量引用版本,因为更匹配;传递常量变量或字面值时则选择常量引用版本。 示例代码: ```cpp #include <iostream> using namespace std; // 示例1:常量引用和非常量引用重载 void func(int &ref) { cout << "non-const reference: " << ref << endl; } void func(const int &ref) { cout << "const reference: " << ref << endl; } // 示例2:不同类型引用重载 void func(double &ref) { cout << "double reference: " << ref << endl; } int main() { int a = 10; const int b = 20; double c = 3.14; func(a); // 调用非常量引用版本 func(b); // 调用常量引用版本 func(30); // 调用常量引用版本,因为字面值30是常量 func(c); // 调用double引用版本 return 0; } ``` 输出结果: ``` non-const reference: 10 const reference: 20 const reference: 30 double reference: 3.14 ``` 注意事项: - 避免函数重载时出现二义性。例如,如果同时定义`void func(int)`和`void func(const int&)`,在调用`func(10)`时,两者都可以匹配,但通常非引用参数和常量引用参数在匹配字面值时都会产生匹配,编译器可能无法决定调用哪个,导致二义性错误。因此,在设计重载时需要谨慎。 总结: 使用引用作为参数进行重载时,可以利用引用的类型(是否为常量、引用哪种类型)以及参数顺序的不同来实现重载。但要注意避免二义性,并理解常量引用和非常量引用的匹配规则。 §§相关问题§§ 1. 函数重载中,使用常量引用和非常量引用作为参数时,编译器如何选择调用哪个函数? 2. 使用引用作为函数参数进行重载时,可能出现哪些二义性问题?如何避免? 3. 引用作为函数参数与指针作为函数参数在重载时有何区别? </think>### 使用引用作为函数参数进行重载的方法和示例 根据引用内容[^2][^4][^5],当使用引用作为函数参数进行重载时,需满足函数重载的基本规则:**函数名相同,但形参列表不同**(参数类型、个数或顺序不同)。引用参数的特性(如非常量引用 vs 常量引用)可用于区分重载函数。 --- #### 方法说明 1. **通过引用类型区分**: - 使用不同类型的引用参数(如 `int&` vs `double&`) - 使用常量引用 `const T&` 与非常量引用 `T&` 区分 2. **通过参数顺序区分**: - 相同类型的引用参数按不同顺序排列 3. **注意事项**: - 返回值类型不同不能构成重载 - 必须初始化引用参数(引用特性要求) --- #### 代码示例 ```cpp #include <iostream> using namespace std; // 示例1:通过引用类型区分重载 void print(int& a) { cout << "int&: " << a << endl; } void print(const int& a) { // 常量引用 cout << "const int&: " << a << endl; } // 示例2:通过参数顺序区分重载 void process(int& a, double& b) { cout << "int+double: " << a + b << endl; } void process(double& a, int& b) { // 参数顺序不同 cout << "double+int: " << a + b << endl; } // 示例3:通过引用类型组合区分 void validate(string& s) { cout << "可修改字符串: " << s << endl; } void validate(const string& s) { // 常量引用 cout << "只读字符串: " << s << endl; } int main() { int x = 10; const int y = 20; double d = 3.14; string text = "Hello"; const string ctext = "Const"; print(x); // 调用 void print(int&) print(y); // 调用 void print(const int&) print(30); // 调用 void print(const int&)(字面量匹配常量引用) process(x, d); // 调用 void process(int&, double&) process(d, x); // 调用 void process(double&, int&) validate(text); // 调用 void validate(string&) validate(ctext); // 调用 void validate(const string&) } ``` #### 输出结果: ``` int&: 10 const int&: 20 const int&: 30 int+double: 13.14 double+int: 13.14 可修改字符串: Hello 只读字符串: Const ``` --- #### 关键点解析 1. **常量引用 vs 非常量引用**: - 常量引用可绑定到字面量或常量(如 `print(30)`) - 非常量引用只能绑定到可修改的左值 2. **参数顺序的作用**: - 当参数类型相同但顺序不同时(如 `(int&, double&)` 和 `(double&, int&)`),编译器能根据实参顺序匹配正确函数 3. **避免歧义**: - 若定义 `void func(int)` 和 `void func(const int&)`,调用 `func(5)` 会产生歧义 - 解决方案:明确设计意图,避免过度重载 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值