C++学习篇(2)

更多精彩请关注微信公众号“爱折腾的码农”,二维码见下图。
C++学习篇(2)_第1张图片

本篇内容主要是分享指针和引用、c++类型转换操作符等内容,我主要是也根据《More Effective C++》、《C++ primer》和一些面经进行总结的。

引用(reference

    定义:为另一个变量起了一个另外的名字(可以直接说变量的别名),通过声明符写成&refival的形式来定义引用类型,其中ival为声明的变量名。

图片

    对于变量别名的理解

C++学习篇(2)_第2张图片

 

引用变量和被引用变量并没有共用一块内存,引用变量其实是另外开辟了一块内存;引用变量开辟的内存里面存放的是被引用变量的地址;任何对引用变量的操作都会转换为对解引用的操作,例如:(*refval)代表的就是ival。

    引用的注意事项

没有空引用,即定义必须初始化;引用总是指向它最初获得的那个对象,即引用将和它初始值对象一直绑定在一起,无法令引用再绑定其他对象。

    

    常量引用注意:​​​​​​​

非常量引用不能绑定在常量上常量引用既可以绑定在常量上也可以绑定在非常量上不能通过常量引用去改变被引用的值

    

    引用分类

C++学习篇(2)_第3张图片

 

左值:有名字,可以取地址,非临时右值:没有名字,不能取地址,临时的(定义方式:类型 && 引用名 = 右值表达式)

    本篇重点讲一下右值引用,因为这在面试中会经常被问到,比如说c++11特性、右值引用的特点。。。

    右值引用

    • 定义:指代临时的对象,它们只在当前的语句中有效。

    • 目的:1、消除两个对象之间不必要的拷贝,节省运算存储资源,提高运行效率(转移语义)2、能够更简洁明确的定义泛型编程(完美转发)。

    • 转移语义:将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C++ 应用程序的性能。临时对象的维护 ( 创建和销毁 ) 对性能有严重影响。

    • 完美转发:在参数传递过程中属性和参数值都不变

    • std::move:将左值引用转换为右值引用,实现转移语义。原理:折叠引用。

图片

 

C++学习篇(2)_第4张图片

 

        接下来就是分析指针和引用的区别。相信学习过c语言的人对指针并不陌生,其实指针就是一种保存变量地址的变量。因为对于每个变量来说都有自己的地址,而指针就是保存这个地址的变量。

C++学习篇(2)_第5张图片

      具体指针和引用区别如下,这里面我只是举了一些常见的内容,还有一些可以自行去网上百度,很多讲的特别详细。​​​​​​​

引用不需要解引用就可以直接获取指向内存空间的值,而指针需要解引用;引用的赋值操作不需要取地址符来赋值,而是通过变量名;但是指针必须通过取地址符来实现;引用必须要初始化,且指向的地址不能被改变;但是指针就更加灵活,可以初始化为空或者不初始化;通过sizeof获取大小不同,指针一般和操作系统位数有关,如32位的指针占4个字节,但是引用是引用对象所占的大小;引用和指针自增结果不同;引用的底层是通过指针实现的;通过malloc/new申请内存的返回值是指针。

 

 

C++强制类型转换

       下面说这一段其实主要是为了引出四种类型操作符,可看可不看,不过z在面试中可以简单介绍一下为什么会出现这四种类型操作符。

        对于C语言来说,它可能会隐式将一种类型转换成其他类型(比如说使用malloc分配内存时,其首先返回void*,然后隐式转换成相应类型的指针),但是这种转换并不能够精确的指明意图。虽然其也提供了一些方式来进行显示的转换,比如说使用一对小括号加上一个对象名称(标志符)组成,如​​​​​​​

float fnum = 1.2;int num = (int)fnum;  //从float转换成int

    由于小括号和对象名称在C++中任何地方都可能被用到,因此为了解决这些问题,C++引入了4种新的类型转换操作符,如下图所示。

C++学习篇(2)_第6张图片

  • static_cast

    格式:static_cast(expression)​​​​​​​

int firstNumber, secondNumber;...double result = static_cast(firstNumber/ secondNumber)

    用途​​​​​​​

用于基本数据类型之间的转换,如把int转换成double用于类类型转换,如派生类和基类之间,但是需要注意这种没有类型安全检查,即基类转换成派生类可能会有问题。把空指针转换成目标类型的指针

 

    注意

static_cast基本上拥有C就是转型相同的威力和意义,以及相同的限制。例如,不能够利用static_cast将一个struct转换成int,或将一个double转换成指针;另外,static_cast也不能去除表达式的常量性。因为有一个新式转型操作符const_cast专司此职。

《More Effective C++》

    

    为什么要用static_cast转换而不用c语言中的转换?​​​​​​​

更安全;更直接明显,能够一眼看出是什么类型转换成什么类型,容易找出程序中的错误;可清楚地辨别代码中每个显式的强制转换;可读性更好,容易被解析,且能体现程序员的意图。(可看《More Effective c++》第二节)

 

  • const_cast

    格式:const_cast (expression)

    用途

用来改变表达式中的常量性或易变性,即将某个对象的常量性去除掉

    注意:const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。 

 

  • reinterpret_cast

    格式:reinterpret_cast (expression),必须是一个指针、引用、算术类型、函数指针或者成员指针

    用途:改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型。不过最常用的是转换“函数指针”类型。

    注意:使用reinterpret_cast强制转换过程仅仅是比特位的拷贝,因此需要特别谨慎
 

  • dynamic_cast

    格式:dynamic_cast (expression)

   用途​​​​​​​

其他三种类型转换都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查;不能用于内置的基本数据类型的强制转换;dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL或者抛出异常;使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过,但是static_cast没有这方面要求。

    需要检测虚函数的原因:1、类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义;2、运行时类型检查需要运行时类型信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。  

C++学习篇(2)_第7张图片来自于网上截图

 

    总结:对于引用部分,相信看面经的人知道问的几率挺多的,特别是右值引用。在回答的时候可以说一下右值引用和左值引用的区别、右值引用的作用、右值引用中转移语义和完美转发实现原理(其实就是折叠引用),然后据一些例子;另外,对于指针和引用的区别,我觉得可以先说引用为什么是变量的别名,接下来引出引用为什么必须要初始化,以及与指针的其他区别;最后,对于c++类型转换部分,可以分成编译时处理和运行时完成两类来讲解这四种类型转换,同时也要记得突出每种转换操作符的重点以及局限性,比如说const_cast主要去除常量性等等。以上只是本人的一些思路,具体还是要看个人情况而定。

你可能感兴趣的:(c++相关知识)