先看一下简单的例子。
void Func1(int x) //这个函数的参数使用值传递方式
{
x = x + 10;
}
//当参数类型更复杂时,指针和引用传递方式在效率等方面的优势更为明显
//不过那样例子就不够“简单”了
void Func2(int *x) //这个函数的参数使用指针传递方式
{
*x = *x + 10;
}
void Func3(int &x) //这个函数的参数使用引用传递方式
{
x = x + 10;
}
以下代码调用这些函数:
int n = 0;
Func1(n);
acutPrintf(“n = %d”, n); // n = 0
Func2(&n);
acutPrintf(“n = %d”, n); //n = 10
Func3(n);
acutPrintf(“n = %d”, n); //n = 20
以上代码段中,当程序调用Func1()函数时,首先在栈(Stack)内分配一块内存用于复制变量n。若变量n的类型复杂,甚至重载了该类的默认拷贝构造函数:
CMyClass(const CMyClass &obj);
这个过程可能会比较复杂。<类的默认拷贝构造函数使用“位拷贝”而非“值拷贝”,若类中包括指针成员,不重载该函数几乎注定程序会出错。关于这个问题以后再深入探讨。>
程序进入函数Func1()体内后,操作的是栈中的临时变量,当函数结束(或者说返回)时,栈内变量被释放。而对于函数Func1()来说的外部变量n并未起任何变化,因此随后的acutPrintf函数将输出n = 0。
程序调用函数Func2()时,在栈内分配内存用于存放临时的指针变量x。然后用&运算取得变量n的地址,并拷贝给临时指针变量x作为x的值。此时,指针x就成了指向变量n的指针。在函数体内,*x运算得到的是指针x指向的内容,即变量n。对*x操作实际上就是对n操作。因此,在函数Func2()中变量n的值起了变化。在分析Func2()函数时应该注意到,临时指针变量x要指向的内存地址,也就是说变量x的“值”仍然是采用了值传递方式从函数外部(或者说函数调用者)获得,那么“值”也就应该具有值传递方式的特点,它要在栈中复制临时变量,它在函数体内被修改不会影响到函数外部。比如说,在上面的代码段中,函数Func2()内可以让指针x指向另外的变量,但函数结束或返回后,在函数外部是无法得到这样的指向另外变量的指针。
程序调用函数Func3()时,临时变量x是一个变量n的引用,此时变量x就是变量n本身,对x操作的同时,外部变量n也起了变化。实际上,引用能做的事,指针也能做到。
以上的代码段确实简单,以至还不能充分显示指针和引用在传递函数参数时的许多其他功能。下面我们设计这样一个函数,函数需要两个参数,在函数内将两个参数的值互换。由于值传递方式尽管能通过返回值赋值的方法修改一个参数值,但不能同时修改两个参数值,因此这个函数不能使用值传递方式。使用指针传递方式,函数可以写成这样:
bool swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
return true;
}
以下代码调用该函数:
/*原文如此
int *a = 10;
int *b = 15;
*/
int a1 = 10 ;
int b1 =15 ;
int *a = &a1 ;
int *b = &b1 ;
if (swap(a, b))
{
acutPrintf(“整数a1,b1已交换数据,*a = %d, *b = %d”,
*a, *b);
}
在以上代码中,swap()函数设计成与常见的ARX函数一致的风格,用一个bool类型返回函数执行状态。<在ARX中,这个返回值通常使用Acad::ErrorStatus类。>在调用函数时,由于变量a和b已经声明为指针,使用标识符a和b访问的是int类型变量的内存地址。
使用引用传递参数,可以这样设计swap()函数:
bool swap(int &x, int &y)
{
int temp;
temp = x;
x = y;
y = temp;
return true;
}
使用代码swap(int a, int b)调用以上函数时,进入函数体内,x、y分别是变量a、b的引用,对x、y操作就是操作变量a、b。函数返回后,变量a、b的值互相交换了。
注意:以上代码只是交换两个变量(或者指针指向的变量)的值。即将变量a、b(或指针a、b指向的变量)的修改为b、a(或指针b、a指向的变量)的值,而不是将指针a指向原来指针b指向的变量。也就是说,swap()函数调用前后,指针a和b的值(地址)并没有发生任何变化。(当然,引用关系在任何时候都不能修改。)要修改指针的地址值,应该使用指向指针的指针或者使用对指针的引用。这样设计和调用函数:
bool swap(int **x, int **y); //使用指向指针的指针传递参数
int *a = 10;//原文如此,不可
int *b = 15;// //原文如此,不可
swap(&a, &b);
或者:
bool swap(int *&x, int *&y); //使用对指针的引用传递参数
int *a = 10; //原文如此,不可
int *b = 15; //原文如此,不可
swap(a,b);
在以上的两个swap()函数以交换两个指针的值,使指针a指向原来指针b指向的变量,指针b指向原来指针a指向的变量。
另外,由于引用关系不可修改,指向引用的指针和引用一个引用没有实际意义。若编译器允许它们存在,实际上也会退化为普通指针(或对指针的引用)和引用。这一点请读者自行分析。
最后,我们看一个ARX程序中使用指针和引用传递参数的函数例子:
AcDbDatabase *pDb = new AcDbDatabase();
AcDbBlockTable *pBlkTbl;
pDb->getBlockTable(pBlkTbl, AcDb::kForRead);
从ARX帮助中可以查看到,getBlockTable()函数的原型是:
Acad::ErrorStatus getBlockTable( AcDbBlockTable*& pTable, AcDb::OpenMode mode);其中可以看到,函数的第一个参数是对一个AcDbBlockTable类型指针的引用,从而可以在函数体内部对指针pBlkTbl进行修改,使之指向pDb指针指向的图形数据库的块表