C++中的引用、auto、范围 for 详解

引用

概念:

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。

格式:

类型& 引用变量名(对象名) = 引用实体;
一个变量可以有多个引用,但一个引用只能专属于一个变量
int b = 10;
int a = 5;
int& c = b; //此处c就是b的引用,也是就b的别名,二者共用一个地址
int& c = a; //这里是不允许的,一个引用只能专属于一个变量,c已经是b的别名了
//引用类型必须和引用实体是同种类型的
int a = 10;
double& c = a; //这里是不行的,double8字节,int才4字节
const double& c = a; //这里就可以了

注意: 引用可以缩小概念,但是不能扩大概念
const int b = 10;
int& c= b;   //这个是不行的,扩大了概念,从const -> int  
const int& d= b;   //这里就可以了

常用的使用场景:

1. 做参数
void Swap(int& a, int& b)  //因为引用和变量共用一块地址空间,所以不用传地址了
{
     
	int tmp = a;
	a = b;
	b = tmp;
}
2. 做返回值
int& Add(int a, int b)
{
     
	int c = a + b;
	return c;
}
int main()
{
     
	int& ret = Add(10, 20);
    add(5,5);
	cout << "Add(10, 20) is :"<< ret <<endl;
}
//本来输出的ret因该是30,但是输出的ret却是10,这是因为ret是返回值的别名,在第二次调用的时候,ret也会改变,故为10,所以一般不会引用做返回值

引用和指针的区别:

引用和指针的区别在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

int main()
{
     
    int a = 10;
    int& ra = a;
    cout << "&a = " << &a << endl;
    cout << "&ra = " << &ra << endl;
    return 0;
   // 在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
}
int main()
{
     
    int a = 10;

    int& ra = a;
    ra = 20;

    int* pa = &a;
    *pa = 20;
    //这里二者的作用是一样的
    return 0;
}

指针和引用的不同点

  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型
    实体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占
    4个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针,但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  8. 引用比指针使用起来相对更安全

auto

概述

C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

用法:

int main()
{
     
    int a = 10;
    auto b = a;   //auto 会自动根据上面的类型去推导
    auto& d = a;
    auto c = &a;
    auto f = c;

   	cout << typeid(a).name() << endl;   //输出为 int
   	cout << typeid(b).name() << endl;   // int
   	cout << typeid(d).name() << endl;   // int
   	cout << typeid(c).name() << endl;   // int *
   	cout << typeid(f).name() << endl;   // int *
    return 0;
}
//在同一行定义多个变量
//当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
void TestAuto()
{
     
	auto a = 1, b = 2;
	auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

auto不能推导的场景

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{
     }
//auto不能直接用来声明数组
void TestAuto()
{
     
    int a[] = {
     1,2,3};
    auto b[] = {
     456};
}

范围for

for循环迭代的范围必须是确定的。对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

int main()
{
     
	int arry[5] = {
      1,2,3,4,5 };
	for (auto& e : arry)  //相当于把arry数组中的每一个值都传给 e
	//这里& 是为了让 e 成为数组值的别名,否则只改变了 e 却没有改变数组本身的值

	{
     
		e *= 2;
	}
	for (auto e : arry)
	{
     
		cout << e << " ";
	}
	cout <<  endl;
}
//这个代码就有问题,因为for的范围不确定
void TestFor(int array[])
{
     
    for(auto& e : array)
    cout << e << endl; 
}

你可能感兴趣的:(C++)