当前位置: 首页 > 科技观察

C++中指针和引用详解

时间:2023-03-17 19:21:28 科技观察

1.指针和引用的定义。为什么会有这些差异。指针的权威定义:在声明TD中,其中D的形式为*cv-qualifier-seqoptD1并且声明TD1中标识符的类型为“derived-declarator-type-listT”,则D的标识符是“derived-declarator-type-listcv-qualifier-seqpointertoT”。cv-qualifiers适用于指针而不适用于指向的对象指针。——摘自《ANSI C++ Standard》注:部分读者可能不理解cv-qualifier-seqCV-qualifiers(CV限定符)CV分为三种类型-限定符:const-qualifier(常量限定符)、volatile-qualifier(易失性限定符)和const-volatile-qualifier(常量-volatile限定符)。const类对象的非静态、非可变和非引用数据成员是const限定的;volatile类对象的非静态、非引用数据成员是volatile限定的;const-volatile类对象的非静态、非引用数据成员是const-volatile限定的。当CV限定符用于限定数组类型时,实际上是数组成员被CV限定符限定,而不是数组类型。复合类型没有被CV限定符限定,因为它的成员被CV限定符限定,也就是说,即使它的成员被CV限定符限定,复合类型也不是CV限定的对象。引用的权威定义:在声明TD中,D的形式为&D1并且声明TD1中标识符的类型为“derived-declarator-type-listT”,则D的标识符类型为“derived-declarator-type-listcv-qualifier-seqreferencetoT”。Cv限定引用是错误格式的,除非通过使用typedef或模板类型参数引入cv限定符,在这种情况下,cv限定符将被忽略。——摘自《ANSI C++ Standard》以上定义是一个乍一看有点难以理解。如果是这样,说明你对C++还不够熟悉,还有很长的路要走。下面用通俗易懂的话概括一下:指针——对于一个类型T,T*是指向T的指针类型,即一个T*类型的变量可以存储一个T对象的地址,而类型T可以是限定词,比如const、volatile等。见下图,所示指针的含义:Reference-引用是一个对象的别名,主要用于函数参数和返回值类型,符号X&表示X类型的引用,见下图,引用的含义如图:#p#2,指针和引用的区别首先,引用不能为空,但是指针可以为空***如前所述上面引用是对象的别名,引用是空的——对象不存在,怎么会有别名!因此,在定义引用时,必须对其进行初始化。因此,如果您有一个指向另一个对象的变量,但它可能为空,那么您应该使用指针;如果变量总是指向一个对象,即你的设计不允许变量为空,那么你应该使用引用。如下图,定义了一个引用变量,如果不初始化,连编译都无法通过(编译时错误):并且声明指针不能指向任何对象。正是由于这个原因,你必须在使用指针之前进行空操作。引文不必。其次,引用不能改变点,对一个对象“至死不渝”;但是指针可以改变点,指向其他对象。解释:引用虽然不能改变指针,但是可以改变初始化对象的内容。例如,就++操作而言,对引用的操作直接响应指向的对象,而不是改变指向;而对指针的操作将使指针指向下一个对象,而不是改变所指向对象的内容。参见下面的代码:#includeusingnamespacestd;intmain(intargc,char**argv){inti=10;int&ref=i;ref++;cout<<"i="<usingnamespacestd;intmain(intargc,char**argv){inti=1;int&ref=i;intx=ref;cout<<"xis"<:8048714:55    push%ebp8048715:89e5   mov%esp,%ebp8048717:83e4f0and$0xfffffff0,%esp//为main函数804871a的参数argc和argv预留位置:56push%esi804871b:53push%ebx804871c:83ec28sub$0x2c4f28,%esp$p)//将0x1保存到esp寄存器中,即inti=18048726:008048727:8d44241clea0x1c(%esp),%eax//将esp寄存器中变量i的地址传给eax804872b:89442418mov%eax,0x18(%esp)//将寄存器eax中的内容(i的地址)传递给寄存器中的变量ref,即int&ref=i804872f:8b442418mov0x18(%esp),%eax//传递寄存器中的refregisteresptoeax,即i的地址8048733:8b00mov(%eax),%eax//以寄存器eax中的值作为地址,取值到eax8048735:89442414mov%eax,0x14(%esp)//将寄存器eax中的值传送给x在寄存器esp中,即x=ref8048739:c7442404008904movl$0x8048900,0x4(%esp)8048740:088048741:c7042440a00408movl$0x804a040,(%esp)8048748:e8cbfeffffcall8048618<_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>804874d:8b542414mov0x14(%esp),%edx8048751:89542404mov%edx,0x4(%esp)8048755:890424mov%eax,(%esp)8048758:e85bfeffffcall80485b8<_ZNSolsEi@plt>804875d:c7442404388604movl$0x8048638,0x4(%esp)8048764:088048765:890424mov%eax,(%esp)8048768:e8bbfeffffcall8048628<_ZNSolsEPFRSoS_E@plt>//从8048739~8048768这些行是为了执行"cout<<"xis"<804879d:89742404mov%esi,0x4(%esp)80487a1:890424mov%eax,(%esp)80487a4:e80ffeffffcall80485b8<_ZNSolsEi@plt>80487a9:c74424040d8904movl$0x804890d,0x4(%esp)80487b0:0880487b1:890424mov%eax,(%esp)80487b4:e85ffeffffcall8048618<_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>80487b9:895c2404mov%ebx,0x4(%esp)80487bd:890424mov%eax,(%esp)80487c0:e8f3fdffffcall80485b8<_ZNSolsEi@plt>80487c5:c7442404388604movl$0x8048638,0x4(%esp)80487cc:0880487cd:890424mov%eax,(%esp)80487d0:e853feffffcall8048628<_ZNSolsEPFRSoS_E@plt>//这几行是为了执行"cout<<"ref="<