1、C++中的指针参数传递和引用参数传递
指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了一个副本。值传递的特点是,被调函数对形式参数的任何操作都是作为局部变量进行的,不会影响主调函数的实参变量的值(形参指针变了,实参指针不变)。
引用参数传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响到主调函数中的实参变量。
引用传递和指针传递是不同的,虽然他们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将应用不到主调函数的相关变量。如果想通过指针参数来改变主调函数中的相关变量(地址),那就得使用指向指针的指针或者指针引用。
从编译的角度来看,程序在编译时分别将指针和引用添加到符号表上,符号表中记录的是变量名极其所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值(与实参名字不同,地址相同)。符号表生成之后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。
2、C++中const和static关键字(定义,用途)
static作用:控制变量的存储方式和可见性
- 修饰局部变量。一般情况下,对于局部变量在程序中是存放在栈区的,并且局部的生命周期在包含语句块执行结束时便结束了。但是如果用static关键字修饰的话,该变量便会存放在静态数据区,其生命周期会一直延续到整个程序执行结束。但是要注意的是,虽然用static对局部变量进行修饰之后,其生命周期以及存储空间发生了变化,但其作用域并没有改变,作用域还是限制在其语句块。
- 修饰全局变量。对于一个全局变量,它既可以在本文件中被访问到,也可以在同一个工程中其他源文件被访问(添加extern进行声明即可)。用static对全局变量进行修饰改变了其作用域范围,由原来的整个工程可见变成了本文进可见。
- 修饰函数。用static修饰函数,情况和修饰全局变量类似,也是改变了函数的作用域。
- 修饰类。如果C++中对类中的某个函数用static修饰,则表示该函数属于一个类而不是属于此类的任何特定对象;如果对类中的某个变量进行static修饰,则表示该变量由该类以及所有的对象所有,存储空间中只存在一个副本,可以通过类和对象去调用。
(补充:静态非常量数据成员,其只能在类外定义和初始化,在类内仅是声明而已。) - 类成员/类函数声明static
- 函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
- 在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
- 在模块内的static函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块内;
- 在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
- 在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量;
- static类对象必须要在类外进行初始化,static修饰的变量先于对象存在,所以static修饰的变量要在类外初始化;
- 由于static修饰的类成员属于类,不属于对象,因此static类成员函数是没有this指针,this指针是指向本对象的指针,正因为没有this指针,所以static类成员函数不能访问非static的类成员,只能访问static修饰的类成员;
- static成员函数不能被virtual修饰,static成员不属于任何类对象或实例,所以加上virtual没有任何实际意义;静态成员函数没有this指针,虚函数的实现是为每一个对象分配一个vptr指针。而vptr是通过this指针调用的,所以不能为virtual;虚函数的调用关系为:this->vptr->ctable->virtual function。
const关键字:含义及实现机制
const修饰基本数据类型:基本数据类型,修饰符const可以用在类型说明符前,也可以用在类型说明符后,其结果是一样的。在使用这些常量的时候,只要不改变这些常量的值即可。
const修饰指针变量和引用变量:如果const位于*号左侧,则const就是用来修饰指针所指向的变量,即指针只想为常量;如果const位于*号右侧,则const就是修饰指针本身,即指针本身是常量。
const应用到函数中:作为参数的const修饰符:调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,保护了原对象的属性。
【注意】参数const通常用于参数为指针或引用的情况;作为函数返回值的const修饰符:声明了返回值后,const按照“修饰原则”进行修饰,起到相应的保护作用。
const在类中的用法:const成员变量,只在某个对象生命周期内是常量,而对于整个类而言是可以改变的。因为类可以创建多个对象,不同的对象其const数据成员值可以不同。所以不能在类的声明中初始化const数据成员,因为类的对象在没有创建时候,编译器不知道const数据成员的值是什么。const成员函数的主要目的是防止成员函数修改对象的内容。要注意,const关键字和static关键字对于成员函数来说是不能同时使用的,因为static关键字修饰静态成员函数不含有this指针,即不能实例化,const成员函数又必须具体到某一个函数。
const修饰类对象,定义常量对象:常量对象只能调用常量函数,别的成员函数都不能调用。
补充:const成员函数中如果实在想修改某个变量,可以使用mutable进行修饰。成员变量中如果想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现或者static const。
3、C++中的const类成员函数(用法和意义)
常量对象可以调用类中的const成员函数,但不能调用非const成员函数;(原因:对象调用成员函数是,在形参列表的最前面加一个形参this,但这是隐式的。this指针是默认指向调用函数的当前对象的,所以很自然this指针是一个常量指针test * const,因为不可以修改this指针代表的地址。但当成员函数的参数列表后加了const关键字,此成员函数为常量成员函数,此时它的隐式this形参为const test* const,即不可以通过this指针来改变指向对象的值。)
非常量对象可以调用类中的const成员函数,也可以调用非const成员函数。