C++引用(1) - 基本介绍

目录

1.基本概念

2.引用vs指针

2.1例子1

2.2例子2

2.3例子3

2.4例子4

2.5例子5

2.6例子6


1.基本概念

当一个变量声明为引用时,它就成为了一个名称可以改变的已存在变量了。可以使用"&"来声明一个变量为引用类型。
#include<iostream>
using namespace std;
int main()
{
  int x = 10;
  //ref是x的引用
  int& ref = x;
  //x的值变成了20
  ref = 20;
  cout << "x = " << x << endl ;
  //x的值现在变成了30
  x = 30;
  cout << "ref = " << ref << endl ;
  return 0;
}
输出:
x = 20
ref = 30
 
下面是一个使用引用来进行值交换的例子。
#include<iostream>
using namespace std;
void swap (int& first, int& second)
{
    int temp = first;
    first = second;
    second = temp;
}
int main()
{
    int a = 2, b = 3;
    swap( a, b );
    cout << a << " " << b;
    return 0;
}
输出:
3 2
 

2.引用vs指针

引用与指针都可以用来在其它函数中修改某个函数中的局部变量。也都可以做为函数参数来传递很大的对象,或者做为函数返回值,以此避免拷贝开销,提高效率。
除去上面所述的相似点,它们之间有下面的这些不同点。
 
引用的功能没有指针那么强大:
1) 一旦引用被创建,就不能用它来再引用其它对象;引用不能被重置。而指针是可以的。
2) 引用不能为空NULL。而指针通常被赋值为NULL来显示不指向任何对象。
3) 引用在声明的时候就必须初始化。而指针并没有这种限制。
 
基于上面的限制,C++中的引用无法用来实现类似链表,树等数据结构。在Java中,引用没有上面的这些限制,可以用来实现任意的数据结构。引用在Java中功能更强大,也是Java无需支持指针的主要原因。
 
使用引用更加安全,容易:
1) 更安全: 因为引用必须被初始化,"wild引用"不可能像"wild指针"一样存在。但是,仍然可能会碰到引用所指向的是一个无效的对象(见下面的例子5和6)
2) 更容易: 引用无需使用解引用操作符来获取其值。它可以像正常变量一样来使用。'&'运算符只是在声明引用的时候需要。另外,一个对象引用中的成员可以使用点操作符'.'来访问,不像指针一样需要箭头操作符'->'来访问。
 
综上所述,只有很少的地方不能用指针,例如拷贝构造函数。在拷贝构造函数中必须使用引用来传递参数。类似地,在重载一些运算符的时候, 也必须使用引用。
 
为了更好的理解引用与指针,参考下面的这些例子。
 

2.1例子1

#include<iostream>
int &fun()
{
    static int x = 10;
    return x;
}
int main()
{
    fun() = 30;
    std::cout << fun();
    return 0;
}
输出:
30
 

2.2例子2

#include<iostream>
int fun(int &x)
{
    return x;
}
int main()
{
    std::cout << fun(10);
    return 0;
}
编译错误。
visual studio 2015提示如下:
“int fun(int &)”: 无法将参数 1 从“int”转换为“int &”。

 
修改为下面代码后,可以正常编译运行。
int x=10;
std::cout << fun(x);
输出:
10
 

2.3例子3

#include<iostream>
void swap(char * &str1, char * &str2)
{
  char *temp = str1;
  str1 = str2;
  str2 = temp;
}
int main()
{
  char *str1 = "the Los Angeles Lakers";
  char *str2 = "the Chicago Bulls";
  swap(str1, str2);
  std::cout<<"str1 is "<<str1<<std::endl;
  std::cout<<"str2 is "<<str2<<std::endl;
  return 0;
}
输出:
str1 is the Chicago Bulls
str2 is the Los Angeles Lakers
 

2.4例子4

#include<iostream>
int main()
{
  int x = 10;
  int *ptr = &x;
  int &*ptr1 = ptr;
}
编译错误:
1.“ptr1”: 指向引用的指针非法
2.“初始化”: 无法从“int *”转换为“int **”
 

2.5例子5

#include<iostream>
using namespace std;
int main()
{
  int *ptr = NULL;
  int &ref = *ptr;
  cout << ref;
}
编译可以通过,但是运行的时候发生了异常。引用ref访问了一个无效的地址 0x00000000.
visual studio 2015调试时抛出异常:"无法读取内存"。
 

2.6例子6

#include<iostream>
using namespace std;
int &fun()
{
    int x = 10;
    return x;
}
int main()
{
    fun() = 30;
    cout << fun();
    return 0;
}
输出:
10
 
将这个例子修改为下面代码:
#include <stdio.h>
#include <iostream>
int& fun()
{
    int x = 10;
    printf("x addr: 0x%p\n", &x);
    return x;
}

int main()
{
    int& y = fun();
    printf("y addr: 0x%p\n", &y);

    int* p = &y;
    *p = 22;
    printf("p addr: 0x%p\n", &p);
    std::cout << fun();
    getchar();
    return 0;
}
则输出:
x addr: 0x003DFDE0  //栈地址
y addr: 0x003DFDE0
p addr: 0x003DFEC4  //栈地址
x addr: 0x003DFDE0
10  //为何是10????与编译器相关。也可能是一个随机值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值