C++入门基础知识点详解(下)

目录

一、C++入门知识点:引用

        1、C++引用:概念

        2、C++引用:特性

        3、C++引用:常饮用

        4、C++引用:引用的使用场景

        5、C++引用:引用和指针的区别

 二、C++入门知识点:内联函数

        1、C++内联函数:概念

        2、C++内联函数:特性

 三、C++入门知识点:auto关键字

        1、C++auto关键字:概念

        2、C++auto关键字:注意事项


         在上篇中,为大家介绍了C++的历史,以及命名空间、缺省参数、函数重载的概念。接下来,将继续为大家介绍C++入门的基础知识点,然后就可以正式开始C++的学习之路了!

一、C++入门知识点:引用

        我们先来看看引用是什么样子的,为什么很多人把引用和指针分不清。(别名的符号& 取地址符&是一个符号,所以不要理解了哦)

int a = 10;
int& b = a;

        1、C++引用:概念

        我们首先要搞明白,引用并不是定义了一个新的变量,而是现在存在一个变量,给这个已存在的变量起了一个别名。编译器不会为了这个别名重新开辟空间去存放数据,因为本质上这个别名和它所引用的变量,共用的是同一块内存空间。请看如下代码运行的结果:

int a = 10;
int& b = a;

printf("a的地址:%p\n", &a);
printf("b的地址:%p\n", &b);

         此时的变量a和他的别名b的地址是相同的,这也就证实了我们之前所说的:别名并不重新开辟空间,而是对原有空间的另一种称呼。那么我们修改别名,原变量会跟着一起修改吗?

        肯定会咯!因为他们是同一块内存地址嘛,所以你想想看,针对这块内存地址的操作,你无论用什么名字去访问这块内存空间,里面的内容都应该是一样的。

b = 20;
cout << a << endl;
cout << b << endl;

        注意:引用类型必须和被引用的对象是同一类型。(当然,别名是不开辟新空间的,原空间是什么类型数据,别名也得是什么类型)

        2、C++引用:特性

  • 引用在定义时,就必须初始化

        引用在定义时就必须初始化的原因其实很简单,因为起别名是针对已经存在变量的一种操作,引用在一开始定义的时候,就必须绑定要操作的变量对象。

  • 一个变量,可以有多个引用(一个实体可以存在多个引用)

         就如同你的名字一样,你可以有大名,有小名,有外号,这些代号都指向你一个人,别人不会认错。

  •  引用一旦定义,就不能修改(一个引用对应一个实体)

         引用一旦被定义(定义的时候会进行初始化,也可以说引用一旦被初始化),就无法修改。因为一个别名是不可以指向两个不同的内存空间的,这就相当于你的名字,同时指代两个人,这是不符合我们常理的。并且如果一个别名,被赋值多次的话,那么在使用的时候也可能会造成歧义。

        3、C++引用:常饮用

        引用类型必须和被引用的对象是同一类型。所以我们在使用引用的时候,要时刻注意我们引用类型以及操作权限是否匹配。假如你使用一个普通的引用类型去引用一个const修饰的类型,那么你的引用就失败了。(因为const修饰的变量具有常属性,你用一个可以修改的类型,去引用不可修改的类型,就会引发权限放大的问题)

int main()
{
	const int a = 10;
	//int& ra = a;    //该语句编译时会出错,a为常量
	const int& ra = a;//正确
	
	//int& b = 10;    //该语句编译时会出错,10为常量
	const int& b = 10;//正确
	return 0;
}

        权限放大的问题,我们在学习C\C++的时候会经常遇到。总的来说,就是我们严格限制的变量,在传递的过程中,可以对他进行一些额外的操作时,就会触发权限放大的问题。严格的讲,变量操作的权限只能平移和缩小(最好是平移)。

        4、C++引用:引用的使用场景

       a、引用做参数

        在前文,我们已经知道了,引用其实本质上也还是针对的同一块地址进行操作。所以传参时传递引用变量,即相当于传递原变量本身过去(针对引用变量的操作,也会在原变量上起作用)。在底层实现里,引用也是类似指针实现的,所以相比于传值传参,引用传参是更节省空间,效率更高的。

void swap(int& a, int& b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
//此时其实相当于a空间里的数据和b空间进行了交换

        b、引用做返回值

        既然引用能传参,那么引用理应也可以当作返回值来传递。但是在引用返回的时候要特别注意,我们返回的数据不能是函数内部创建的局部变量。因为在函数内部定义的局部变量,在该函数结束调用之后,函数空间会销毁。此时继续访问该变量,会发生内存泄漏。因此,当我们要使用引用返回时,必须要注意变量的生效区间。一定得是static修饰的静态变量,或者是动态开辟在堆上,或者是全局变量的情况,才可以使用引用做返回值。(因为以上情况,函数调用结束后,数据不会被销毁,可以继续访问)

int& Add(int a, int b)
{
	static int c = a + b;
	return c;
}
//总结一句话:
//如果函数返回值时,除了作用域,而返回对象的数据还未归还给系统时,则可以使用引用返回
//如果已经还给系统了,那么必须使用传值返回(传值返回的本质是:对当前数据进行了拷贝,返回的是这个拷贝,所以函数结束也不会影响)

        5、C++引用:引用和指针的区别

        在语法概念上,引用就是已存在变量的一个别名,他没有自己的独立空间,和引用的对象公用的是一块空间。而指针,则是专门开辟了一个独立的内存,来存放这要操作的内存空间的地址。

int a = 10;
int& b = a;
printf("a的地址:%p\n", &a);
cout << sizeof(a) << endl;
printf("b的地址:%p\n", &b);
cout << sizeof(b) << endl;

int c = 10;
int* d = &c;
printf("c的地址:%p\n", &c);
cout << sizeof(c) << endl;
printf("d的地址:%p\n", &d);
cout << sizeof(d) << endl;

        但是我们可以看到,为什么这里别名b实际上还是有大小的呢?其实这就和引用的底层实现有关系了。

 实际上,引用的底层实现其实也是类似指针存地址的方式来处理的。

   引用和指针的区别

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

 二、C++入门知识点:内联函数

        我们在运行一个程序的过程中,势必会进行调用函数这个操作。而一旦调用函数,就会在内存中开辟栈帧(call),多次调用之后,则可能会造成过大的内存消耗。C++为了避免这种情况,允许将函数定义在内部(inline),但是使用inline关键字,并不是百分百就可以把函数定义为内联,这也与编译器的处理有关。一般来说,转成汇编10行以内的函数都可以被定义为内联函数。

        1、C++内联函数:概念

        inline函数,是一种用空间来换时间的做法。如果我们频繁地调用函数,会造成过大的内存消耗;将函数定义为内联函数,则可以避免调用这步操作,函数会在inline位置直接展开。汇编如下:

//设定sum函数为内联函数
inline int sum(int a, int b) 
//sum函数为普通函数
int sum(int a, int b)
{
	return a + b;
}

int main() 
{
	int c = sum(10, 20);
	printf("%d\n", c);

	return 0;
}
sum函数非内联的情况
sum函数为内联函数

        2、C++内联函数:特性

        前文我们已经说过了,内联函数是一种用空间来换时间的做法,但是这种做法也有弊端。

        一是内联函数不适用于递归函数和一些较长的函数,因为这样会造成函数体的臃肿。内联只适用于一些短小的,调用平凡的函数。

        二是inline关键词,对于编译器来说只是一个建议,并不能强制编译器将函数定义为内联函数。函数最终如何使用,取决于编译器的处理。

        三是内联函数的展开特性,决定了内联函数最好是定义和生命不要分离编译。在程序链接阶段,分离的情况会造成链接失败。因为当内联函数在调用处被展开之后,就找不到函数地址了,链接就会失败。

 三、C++入门知识点:auto关键字

        要说C++对于C来说,最大的进步是什么?必不可少的就是对于类型的操作,譬如printf函数在打印时,必须强调打印数据的类型;而C++的cout,则比printf要机灵许多,我们只需要将变量放进去,他就会自动识别。而我们今天学习的auto关键字,也具有这样的逻辑。

        1、C++auto关键字:概念

        在早期的C/C++中auto的含义是:使用auto修饰的变量是具有自动存储器的局部变量,但遗憾的是一直没有人去使用它。
 在C++11中,标准委员会赋予了auto全新的含义:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

int main()
{
	int a = 10;
	auto b = a;

	char c = '0';
	auto d = c;

	cout << typeid(a).name() << endl;
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;

	return 0;
}

       

         根据打印的结果来说,我们在没有给定b和d的情况下,编译器自动为我们识别出来,变量b和变量a是同一类型,变量d和变量c是同一类型。这一切都取决于编译器的处理。因此,在使用auto关键字的时候,我们要注意不要产生歧义。譬如:auto在同一行定义多个变量时,需要统一变量类型。

int main()
{
	int a = 10;
	auto b = &a;   //自动推导出b的类型为int*
	auto* c = &a;  //自动推导出c的类型为int*
	auto& d = a;   //自动推导出d的类型为int
    //在使用auto声明引用变量时,必须添加&

	cout << typeid(b).name() << endl;//打印结果为int*
	cout << typeid(c).name() << endl;//打印结果为int*
	cout << typeid(d).name() << endl;//打印结果为int

    auto m = 10, n = 20;//正确
    auto x = 1, y = 1.1;//错误,前后数据类型不匹配。

	return 0;
}

        2、C++auto关键字:注意事项

  • auto类型的变量不可以作为函数的形参,因为没有实际类型可以给auto变量来推导。
  • auto不能来声明数组,因为auto其实只是一个占位符,并不是实际的声明。编译器会在编译的过程中将auto替换为对应的数据类型。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值