引用和函数重载

const

在C语言中定义常量用宏定义比较多

#define PI 3.14
int main()
{
   double r, area;
   ...
   area = PI * r * r;
   ...
}

但是宏只是简单的文字替换,不能进行类型检查。C++中可以使用const关键字修饰变量,使变量不能修改,让变量当作命名常量使用

const double PI = 3.14;
int main()
{
   double r, area;
   ...
   area = PI * r * r;
   ...
}

引用

C语言的函数是传值的。在函数被调用时,函数的参数变量创建出来并接受实际参数的值,但是它与实际参数是不同的变量,函数调用结束参数变量就不存在了。以交换两个变量的值swap函数为例,

#include <iostream>
using namespace std;

void swap(int x, int y)  // x和y是(形式)参数变量,函数调用时创建,调用结束就不存在了
{
    int t;
    t = x;
    x = y;
    y = t;
}
int main()
{
    int a, b;
    cin >> a >> b;

    swap(a, b); // a和b是实际参数,它们的值被传递给了参数变量x和y

    cout << a << " " << b << endl;

    return 0; 
}

函数传值

swap交换的x和y是a和b的副本,故a和b本身并没有被交换。

怎样在函数内部修改函数外部变量的值呢?可以用指针来处理,

#include <iostream>
using namespace std;

void swap(int *p, int *q)  // 形式参数是指针类型的变量
{
    int t;
    t = *p;
    *p = *q;
    *q = t;
}
int main()
{
    int a, b;
    cin >> a >> b;

    swap(&a, &b); // a和b是实际参数,它们的地址值被传递给了指针变量p和q
    cout << a << " " << b << endl;

    return 0; 
}

函数传地址

由于p指向的a,q指向了b,那么*p就是a的别名,*q就是b的别名,在函数中交换*p和*q的值就是交换a和b的值。

在C++中,要达到上述swap函数的效果,还有一种方式,就是将参数的参数声明为引用类型。引用类型变量和指针变量作用相似,用来给变量起别名。下面来了解一下,

int a = 10;
int &ref_a = a;  // 定义引用类型的变量ref_a,注意&这里不是取地址的意思,只是定义ref_a为引用类型的标志
cout << ref_a << endl;
ref_a = 20;
cout << a << endl;

引用1

相比指针类型的变量,引用类型的变量使用更简单,它本身就是被引用变量的别名。

引用变量使用时有如下特点:

  • 定义时必须以同类型的变量初始化引用变量(不像指针还存在“空指针”和“野指针”)

  • 引用变量初始化以后就一直是那个变量的引用了(“从一而终”)

int a = 10, b = 20;
int &ref_a = a;
ref_a = b;  // 将b的值赋给ref_a,即a;而不是让ref_a成为b的引用的意思
cout << a << endl;
cout << ref_a << endl;
cout << b << endl;

reference-2

引用变量的特点使它也适合做函数的参数变量,swap函数还可以写为

#include <iostream>
using namespace std;

void swap(int &x, int &y)  // 形式参数是引用类型的变量
{
    int t;
    t = x;
    x = y;
    y = t;
}
int main()
{
    int a, b;
    cin >> a >> b;

    swap(a, b); // a和b被x和y引用

    cout << a << " " << b << endl;

    return 0; 
}

函数传地址

函数调用的过程是函数被调用时会建立形式参数变量,并将实际参数变量的值传给形式参数变量,如果形式参数不是指针或者引用变量,形式参数将会是实际参数的副本,如果形式参数是指针,那么实际参数的地址值将会传给它。

引用变量常以指针常量来实现,因此如果形式参数是引用类型,也是传实际参数的地址值。它们不是实际参数的副本,而是可以间接地访问实际参数本身。

同理,如果函数调用时要传很大的对象的信息,比如下面的自定义类类型

class Large{
    int int_arr[100];
    string str_arr[100];
    ...
}; 

形式参数一般也会写为指针或者引用类型。这是因为指针或者引用变量本身占的空间较小(在32位系统上占4个字节)。而且调用时传递的仅仅是对象地址值。反之,形式参数变量与实际参数变量是相同类型的话,形式参数对象将会和实际参数对象占用一样大小的空间,可想而知,这样的对象之间赋值也会比较耗时。

综上,在下述情况下可以使用指针或者引用类型的参数变量:

  • 函数要修改实际参数

  • 函数参数对象占较大空间时

函数重载

在C++程序里,可以存在命名相同的函数,只要函数的参数的区别大到通过函数调用语句编译器可以确定到底调用的是哪一个函数即可。比如上述三种swap函数

  1. void swap(int x, int y); // 调用语句swap(a, b);
  2. void swap(int *p, int *q); // 调用语句swap(&a, &b);
  3. void swap(int &x, int &y); // 调用语句swap(a, b);

函数2可以和函数1或者函数3写在一个程序中。因为函数2的调用形式和1或者3是不同的。但是如果函数1和函数3在一个程序中,而调用语句写为swap(a, b),此时编译器就不确定程序员到底想调用函数1还是函数3,这时就称为函数重载就是不明确的。

#include <iostream>
using namespace std;

void swap(int x, int y)
{
    int t;
    t = x;
    x = y;
    y = t;
}

void swap(int &x, int &y)
{
    int t;
    t = x;
    x = y;
    y = t;
}
int main()
{
    int a, b;
    cin >> a >> b;

    swap(a, b);  // 被调函数不明确,编译出错

    cout << a << " " << b << endl;

    return 0; 
}

上述程序编译无法通过。

试一试,将上述程序中swap(a,b);修改为swap(10, 20);此时程序可以编译通过吗?为什么?

上一篇:C和C++中字符串操作

下一篇:封装(1.类和对象)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值