引用即绑定到另一个对象上,因此定义了一个引用,对其操作即是对与之绑定的对象进行操作(如为引用赋值,获取引用的值,以引用作为初始值...)。
定义引用时是绑定对象,因此必须在定义引用同时必须初始化。 引用本身不是对象,只是另一个对象的别名,因此不能定义引用的引用,也不能定义引用的指针。 引用本身非对象,因此不能进行赋值和拷贝,一旦定义了引用,其只能绑定这个对象,无法再绑定别的对象。但一个对象可以定义多个引用。 引用的类型要与之绑定的对象严格匹配(不支持类型转换),并且引用只能绑定在变量/对象上,不能绑定字面值或者表达式上(即形参为string &str;时,必须使用变量初始化,“hello word”初始化将编译出错)。——两个例外情况与引用类似,实现对对象的间接访问。
指针允许在定义时进行初始化,此时将执行默认初始化。 指针本身是对象,因此可以定义指针的引用,可以对指针赋值和拷贝(对指针赋值即是存放新的地址,指向新的对象),因此在其生命周期内可以先后指向不同对象。并且一个对象可以定义多个指针。 初始化为空指针,即不指向任何对象。(int *p=0;或者int *p=nullptr;均可以。 但是int i=0; int *p=i; 不是初始化空指针语句。) 指针类型和它指向的对象类型必须严格匹配(不支持类型转换),并且指针只能指向变量/对象,不能指向字面值或者表达式。——两个例外情况引用不是对象,指针本身即是对象。
都需要类型和对象类型严格匹配(不支持类型转换),并且指针只能指向变量/对象,不能指向字面值或者表达式。同时,也都对常量指针和常量引用出现例外情况,即这两种情况下可以使用一般的初始化。
1、试图拷贝或者以其他形式访问一个无效指针将引发错误,访问无效指针的后果无法预计,并且编译器不检查此类错误,在设计程序时,必须清楚所有指针的有效性;
2、第2和3种指针虽然有效,但并不指向任何具体对象,因此访问此类指针的对象也不允许。
因此:建议初始化所有指针,并且尽量在定义了对象之后,再定义对象的指针。如若不清楚指针的指向,可以暂时初始化为nullptr或0 ,此时编译器即可以知道所有指针的指向。
前提:指针有效。
如if(p)... 空指针,条件为0;其他有效指针,条件为1 。
如if(*p)... 表示指针指向的对象作为条件判断。
比较两个指针是否相等。相等情况有三:都为空指针;都指向同一对象;都指向同一对象的下一个地址。
const只是个限定符,限定了不能改变其值,此限定只在要改变const变量的值时才起作用。
const对象一旦创建即不能改变其值,因此const对象必须在定义时初始化(普通初始化——直接、隐式、表达式、常值、变量) const限定只在改变其值时限制,对其他操作并不影响。因此和普通初始化相同,可以用变量、常量初始化,也可以进行隐式地类型转换。同时也可以拷贝const对象,并赋值给常量对象或者变量对象(因为对变量的拷贝不会改变对象的值,赋值会改变对象的值)。 定义并初始化一个const变量,则编译器会在整个文件中将所有用到const对象替换成其初始值。 即使用常量初始值代替const对象 多文件使用const对象,需要在声明和定义中都加extern关键字const int ci=2017;
const int &ri=ci;
对常量的引用可以绑定常量和非常量,但是const限定了 不能通过引用改变其绑定对象的值,但可以通过别的方式改变对象的值(直接给对象赋值,或者定义一个新的普通引用)。当然,无论是加不加const,都可以使用解引用或者用引用直接赋值等普通操作(如 int i1 = 0; const int &ci = i1; int i2 = ci; 可以用常量引用给普通变量赋值)。对常量的引用可以普通初始化,可以绑定非常量,但常量对象必须用对常量的引用绑定(但常量对象可以赋值给常量或变量对象)。
指向常量的指针 可以指向非常量(普通初始化),但要存放常量的地址必须使用 指向常量的指针。
(1)指针是对象,引用不是对象,因此允许把指针定义为常量,即常量指针。
常量指针必须初始化,初始化完成后,不能改变指针的值,即不能改变指针的指向地址。(和普通限定下的对象一样,可以用常量指针赋值给常量或变量指针,且是普通赋值) 变量地址存储为常量指针 int errNumb=0; int *const curErr=&errNumb;常量地址存储为指向常量的常量指针 const double pi=3.14; const double *const pip =π 而能不能改变常量指针指向的变量的值,完全依赖于对象的类型。 (2)引用和指针操作不同,引用相当于绑定对象的别名(对对象的直接访问),指针是存放对象的地址(解引用,为间接访问)。 因此引用“ 无论是加不加const,都可以使用用引用实现直接赋值等普通操作,因为此时相当于使用了对象(如 int i1 = 0; const int &ci = i1; int i2 = ci;编译通过, 可以用常量引用给普通变量赋值)。”而指针“ 无论是加不加const,都可以使用解引用等普通操作,但不能把存放了 指向常量的指针 赋给另一个普通指针(int i = 0; const int *pi1 = &i; int *pi2 = pi1;编译出错,不能用 const int * 初始化 int *)。”对const的引用和指向常量的指针都是对引用和指针的限定,不能通过引用或指针方式改变对象的值。
而常量指针,const限定的是变量类型,和前边的const限定符一样,即不能改变变量的值,在常量指针下,即是不能改变指针的指向。
实际上是对 非常量引用、非常量指针、普通类型限定(包括常量指针)、对const的引用、指向const的指针 初始化和赋值的总结。
但是对于引用和指针的使用,不通过绑定或指针改变对象的值,因此可以进行普通赋值和解引用操作 或 其他改变对象值的操作。(如 const int & ci=i1; int i2=ci; 此处是使用引用操作,而不是绑定常量对象)
顶层const:作用于对象本身的 const,即对变量const;对指针本身const(常量指针) 底层const:对引用和指针的限定 对象拷贝操作时,顶层和底层const区别比较大: 顶层的const作用于对象本身,即是普通的类型限定,因此定义时必须初始化,且支持普通初始化——直接、隐式、表达式、常值、变量,也即支持用顶层const对象初始化。而顶层const当然可以作为被拷贝对象,因为拷贝不会改变对象的值(如 const int i1= 's' ; int i2=i1;)。 底层const作用于引用和指针限定,即是 对常量的引用 和 指向常量的指针。因此常量对象只能用 对常量的引用 或者 指向常量的指针 绑定或者存储;而 对常量的引用 和 指向常量的指针 可以 绑定或者指向 非常量对象(即引用和指针的例外情况),但非常量引用或指针不能绑定或指向常量对象(因为引用和指针要求类型严格匹配)。