Conference pointer and const
CPPP P45-60
引用-取别名(同等异名)
引用,也就是为了给变量取别名,因此,他引用的是变量名、表达式而不是常量;同时,引用必须要初始化,一旦引用完成,引用将和它的初始值对象一直绑定在一起,不能将引用重新绑定在另一个对象上;不能定义引用的引用。但是可以有一例外:
const &p = 10 ; 是合法的
需要特别理解注意:引用不是对象。所以没有引用的引用,因为,引用无法再引用一个已经引用了的变量(它此时不是对象了)。
指针-指向内存地址(指向对象)
指针,也就是将用一变量直接指向一内存中的地址,它必须要赋初始值(在C++中所有的定义的变量都是要赋初始值的),空时,可以指向ullptr;指针及其指向的内存地址中的变量可以改变值;无返回类型时,可以定义为void*。
指针其实也是一种类型,所以可以叫为“指针变量”,它是一对象,所以有指向指针的指针,它的意义是内存的多重指向。
还有,如果定义了指针
int *P = q ;
那么在后面,*p其实就是代表指向q的内存地址的值,也就是等价于q(在取值上),*是解引用符号;P其实就是指针(变量)。还有如果int *j = nullptr; ,那么,w = j ; 语句就是将w指针与j指针等起来,所以w 就是p 了(在指针指向的内存地址上,也就是q的值上)。
补充:关于指针的值的问题
-
指向一个对象 *p = q;
-
指向紧邻对象所占空间的下一个位置 在链表中
-
空指针,意味着指针没有指向任何对象 *p = nullptr;
-
无效指针,也就是以上之外 :-( 没遇到过? 也就是说指针的错误用法吧,也许
Const限定符-固定死值(常量引用)
引用就是将一个值、变量、表达式“固化”到一个变量、引用、指针上。注意,它必须要初始化。与引用和指针不同的是,一旦“固化”了,那么,不可以将它再改值。同理,const的引用固化引用,不可改,但是有一特例:
Const int &p = 10; //OK,因为p是一个“常量引用”
Int&p = 10 ; //ERROR,因为引用类型的初始值必须要是一个对象
同时,注意在const中对引用、指针的两两之间的同一操作关系,就好比如double变量从语法上来讲必须与同是double类型的变量来进行赋值、代数运算等等。
其他:顶层const(最死const) constexpt和常量表达式(常量const)
顶层const,也就是不可改的固定死的const,而底层const,是可以改变的,一般的底层的底层const 是跟指针一起使用的。在多重的const限定符、引用和指针中,看除基本变量类型外的最左边的修饰符,其他的是对这个(基本类型+第一修饰符的)变量的多层修饰,也就是说,从右向左读变量的修饰符即可。例如:
Inti = 0;
Int*const pi = &I ; //顶层const,不能改变p1的值
Constint ci = 42; //顶层const,不能改变ci的值
Cosntint *p2 = &c1 ; //底层const ,可以改变p2的值
Constint *const p3 = p2 ;
//靠左的const是底层const ,靠右的const的是顶层const
Cosntint &r = ci; //用于声明引用的const都是底层const
常量表达式,也就是,“常量”的“表达式”,即是const + 基本数据类型,必须初始化!!!!。只要变量是一个常来那个表达式,那么就应该声明为constexpr类型,但是应该是简单的字面值类型(算数类型、引用和指针),而类、IO库、string库等都不是。在constexpr与指针中,初始值只能够是nullptr或者是0,同时,在constexpr中,限定的只是对指针有效,而对指针所指的对象无关,例如:
Constint *p = nullptr ; //p是一个指向整型常量的指针
Constexprint *q = nullptr; //q是一个指向整数的常量指针
也就是说,p是一个“指向常量的指针”,而q是一个“常量指针”,constexpr把它所定义的对象置为顶层const 。
附:以上相关的见下代码:
#include<iostream>
int main()
{
//pointer and constant
int i = 10;
int *p = &i;
i = 20;
std::cout << " i : " << i << std::endl;
std::cout << " *p : " << *p << std::endl;
*p = 30;
std::cout << " i: " << i << std::endl;
std::cout << " *p " << *p << std::endl;
std::cout << "----------------------------------------------------------------" << std::endl;
//reference and constant
int j = 1;
int &q = j;
j = 2;
std::cout << "j :" << j << std::endl;
std::cout << "q :" << q << std::endl;
q = 3;
std::cout << "j :" << j << std::endl;
std::cout << "q :" << q << std::endl;
std::cout << "-----------------------------------------------------------------" << std::endl;
// const and initialization
int c = 9;
const int c1 = c;
int const c2 = c;
std::cout << "c1 :" << c1 << std::endl;
std::cout << "c2 :" << c2 << std::endl;
std::cout << "c :" << c << std::endl;
//it's wrong c1 = 8;
//it's wrong c2 = 7;
c = 6;
std::cout << "c1 :" << c1 << std::endl;
std::cout << "c2 :" << c2 << std::endl;
std::cout << "c :" << c << std::endl;
std::cout << "-----------------------------------------------------------------" << std::endl;
//const and reference
int r = 55;
const int &r1 = r;
std::cout << " r: " << r << std::endl;
std::cout << " r1: " << r1 << std::endl;
r = 44;
//it's wrong r1 = 33;
std::cout << " r: " << r << std::endl;
std::cout << " r1: " << r1 << std::endl;
std::cout << "----------------------------------------------------------------" << std::endl;
//const and pointer
const double pi = 3.14;
//it's wrong double *ptr =π //because ptr is not a consttype
const double *ptr = π
std::cout << "pi: " << pi << std::endl;
std::cout << "*ptr: " << *ptr << std::endl;
//it's wrong *ptr = 42;
std::cout << "one more :" << std::endl;
int errNumb = 0;
int *const curErr = &errNumb;
const double pp = 3.1415926;
const double *const pip = &pp;
std::cout << "errNum: " << errNumb << std::endl;
std::cout << "*curErr: " << *curErr << std::endl;
std::cout << "pp: " << pp << std::endl;
std::cout << "*pip: " << *pip << std::endl;
errNumb = 99;
//it's wrong pp = 88; because pp is aconst and can't be changed
std::cout << "errNum: " << errNumb << std::endl;
std::cout << "*curErr: " << *curErr << std::endl;
std::cout << "pp: " << pp << std::endl;
std::cout << "*pip: " << *pip << std::endl;
std::cout << "---------------------------------------------" << std::endl;
return 0;
}