最近工作不忙,闲来再次看了下关于C++的书,就总结了一些常用知识的用法及注意点。不是很全面,只是自己的一些见解。
1、引用介绍
简而言之,引用就是一个对象的别名,它通常用于函数的参数表中及函数返回值中,当然也可以独立使用。如下:
int iVal;
int &iRef = iVal;
此时iRef就是iVal的引用,我们可以通过iRef来修改iVal,此处应注意:引用在创建时就应该初始化为指向一个已存在的对象,并且引用一旦被初始化就不可以修改其指向。
2、const引用
const引用很明显就是指向const对象的引用,如:
const int iTest = 14;
const int &iRefTest = iTest;
此时的iRefTest就是一个const引用,我们可以通过它来读取iTest的值但是却不能修改iTest的值,同时应注意:非const引用不能指向const对象,因为这样可能会修改const对象的值,所以这是不被允许的。
所以:非const引用只能指向非const同类型的对象,但是const引用可以初始化为不同但相关的类型的对象或者初始化为右值。
3、函数中的引用
在函数中引用的使用是很广泛地,最经常见到的就是函数的参数和函数的返回值,当引用被用作函数的参数时,任何对引用的更改都会改变函数外的参数;当引用被用作函数的返回值时,我们必须像对待指针一样对待返回的引用,当函数返回时,不管返回的引用关联的是什么都应该是存在的,否则我们将不知道引用指向哪个内存区域。
如下面这样:
int& Fun()
{
int iTemp = 5;
return iTemp;//这样就是不行的,因为当函数结束时,iTemp作为局部变量被释放了,已经不存在
static int s_iTest = 5;
return sITest;//这样就是可以的,因为s_iTest存在于全局静态区,所以直到程序结束就不会释放
}
上面大致说了下引用的使用,下面来具体介绍下引用作为函数参数及返回值的用法及注意点。
(1)引用作为函数的参数
在这里我们把函数参数分为非引用形参和引用形参两类来介绍。
非引用形参:
非引用形参我们又可以分为一般的值传递及指针传递,第一类是值传递,一般的值传递从字面意思上就可以看出来就是单纯的值的传递,即通过复制传递的实参的值来实现形参的初始化,但是这样我们在函数中锁进行的操作都是对实参的副本来进行的,而实际上的实参没进行任何操作,当函数结束时,形参也就不再存在。第二类是指针形参,指针形参顾名思义就是传递的是地址,实际上同样是值传递,只不过传递的地址值,此时当我们对传递的参数的值进行操作时,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。所以当我们修改局部变量时,同时修改了实参指向的值,但是如果我们在函数中修改形参的地址指向却不会修改实参的指向,临时变量虽然是实参的副本,但只是表示指向相同,但是本质上是两个不同的指针。
下例说明指针传递的过程:
void FunPtr(int *pIVal)
{
*pIVal = 5;//ok,修改了pIval所指向的对象的值
pIVal = 0;//ok,pIVal置为0,但是传递的参数的值并没变,这里改变的只是临时变量的值
}
引用形参:
引用形参在C++中用途很广泛,C++也推荐使用引用作为形参,而非用指针,指针本质上依然是值传递,但是引用不是,引用形参实际上是传递的实参的别名,实际上就是传递的实参,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址,被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量,正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
引用形参我们同样可以分两类来介绍:1、非const引用形参,2、const引用形参。
const引用形参与非const引用形参有什么区别,用法又有什么不同呢?
非const引用于const引用都能起到避免参数复制的麻烦,但是const引用同时保证参数值得不变性以及程序的安全性,即const引用形参在函数中是不可修改的,如果修改就会产生编译错误。
如果一个函数的参数时非const形参那么就不能传递常量对象,但是如果是const引用形参,则可接受任何相关类型的对象,但是对于用户自己建的类型,如果传递的参数为引用时,如果是const引用,则调用时,只能使用对象的const函数,而不能调用非const函数。如下例:
class ClassTest
{
public:
void print()
{
cout << "hello world!" << endl;
}
};
void Fun(int &iVal)
{
}
void FunConst(const int &iVal)
{
}
void FunClass(const ClassTest & test)
{
test.print();//error print为非const函数,所以不能被调用
}
int main()
{
Fun(1);//error,非const引用初始化为const对象的引用
FunConst(1);//ok,const 引用初始化为右值的引用
int iValTest = 1;
Fun(iValTest);//ok,非const引用初始化为非const对象的引用
FunConst(iValTest);//ok,const引用初始化为非const对象的引用
FunClass(ClassTest());//error,创建的临时对象为const引用
}
然后下面简要介绍下引用作为返回值的用法,因为本章主要想介绍下参数的使用,所以返回值就讲一下使用时的一些注意点,引用作为函数返回值与指针作为返回值一样,返回值所指向的对象必须是确实存在的,不存的对象是不能返回引用的,函数返回时如果返回的是一个确切的值会产生一个临时变量作为函数返回值的副本,而返回引用时不会产生值的副本,只是返回的对象的别名,在一个函数中返回局部变量的引用时没用意义的。
好了,就先说这么多,也不是太全面,只是自己使用时的一些小体会,引用在C++中的使用非常广泛,尤其是在函数的形参上,所以虽然是基础知识,但是还是应该注意一下它的使用,因为平常使用时,用不好就会出现问题。