1. 引用
引用是
相对于
增加的新概念。首先,在
中,引用的格式为类型名& 引用名 = 某变量名。如int& r = a;
,则定义了一个指向变量a
的引用r
,r
的类型是int&
。首先来看一下
和
中交换函数
的书写:
// C
void swap(int* a, int* b){
int temp;
temp = *a; *a = *b; *b = temp;
}
// C调用,这里&不是引用,而是取地址符号
swap(&m, &n);
// C++,这里&表示引用
void swap(int& a, int& b){
int temp;
temp = a; a = b; b = temp;
}
// C++调用
swap(m, n);
观察上面,有了引用的概念后, 函数的实现和调用变得更加简洁。注意,某个变量的应用,就等价于该变量,相当于该变量的一个别名。如果变量名所指向的值改变时,引用名对应的值也会改变。如:
int m = 5;
int& n = m; // 定义n为变量m的应用
n = 6;
cout << n << ""; // 输出6
cout << m << ""; // 输出6
m = 7;
cout << n << ""; // 输出7
关于引用需要注意的几点:
(1)定义引用时要将初始化成引用某个变量;
(2)一旦初始化后,只会一直引用该变量,不会再引用其他变量;
(3)引用只能引用变量,不能引用常量和表达式。
2. const关键字
在
中,
关键字用于定义一个常量。如const int MAX = 100;
则定义了一个
型的常量
,其值为
。在
语言中定义常量使用
关键字,如#define MAX 100
。相比较而言,
关键字定义常量时有类型检查。此外,还可以利用关键字
定义常量指针,如const int* p = &n;
其中
都是整型变量。对于常量指针,需要注意几点:
(1)不可通过常量指针修改其指向的内容;
(2)不能把常量指针赋值给非常量指针(可以通过强制类型转换),反之可以;
(3)函数参数为常量指针时,可避免函数内部对参数指针所指内容的修改。如:
int m, n;
const int* p = &n; // p是一个常量指针,指向n
*p = 5; // 编译出错,不能通过常量指针修改其指向的内容
n = 6; // 正确,可以通过变量本身修改其内容
p = &m; // 正确,常量指针的指向可以改变
const int* p; int* q;
p = q; // 正确
q = p; // 出错
q = (int*) p; // 通过强制类型转换将常量指针赋值给非常量指针
void func(const char* p){
strcpy(p, "hello"); // 出错,企图修改常量指针所指内容
printf("%s", p); // 正确,打印函数不修改p
}
综合引用和
关键字可以定义常引用,其形式为const int& p = q;
。则常引用的性质为不能通过常引用修改其引用的内容,但可以通过变量本身修改其内容,且
的值随着
的改变而改变。注意,const T&
和T&
为不同类型,后者可以初始化后者,反之不行(除非进行强制类型转换)。
3. 动态内存分配
在程序运行过程中,有时候需要进行动态内存分配。在
语言中动态内存分配采用关键字
,其形式为int *p = (int *)malloc(sizeof(int));
,则为
申请一个
型变量大小的空间。在
中使用
关键字完成动态内存分配。其具有两种基本用法:
第一,分配一个变量。如P = new T;
,完成的功能是动态分配出一片大小为
的内存空间,并且将该内存空间的起始地址赋值给
。
第二,分配一个数组。如P = new T[N];
,完成的功能是动态分配出一片大小为
的内存空间,并将该内存空间的起始地址赋值给
。
在
中使用
关键字动态分配内存空间,在程序结束前,需要将不用的内存空间释放掉,这里使用关键字
。其形式为delete 指针;
,这里的指针必须指向
关键字分配的控件。关于
关键字需要注意几点:
(1)不能delete多次;
(2)delete数组时候,加上
,否则只能释放一个位置,没有释放的空间在程序运行期间就浪费了。如:
int *p = new int; // 动态分配一个变量
*p = 5;
delete p; // 成功
delete p; // 错误,不能delete多次
int m = new int
int* p = new int[10]; // 动态分配一个数组
p[0] = 5;
delete p; // 没有完全释放分配的内存空间
delete []p; // 正确释放所有分配的内存空间
4. 内联函数
- 函数调用有额外开销:调用函数时首先将参数放入栈中,函数的返回值也要放入栈中。执行完函数后,再从栈内取返回值。如果函数本身只有几条语句,而且被反复调用多次。相比之下函数调用所产生的额外开销就比较大。
- 为了减少函数调用的开销,引入了内联函数机制。编译器在处理内联函数的调用语句时,不同于普通函数的调用,而是将整个函数的代码插入到调用语句处。即内联函数调用时不会产生上述栈的操作。
- 在 中使用 关键字定义内联函数。
- 为了保证效率,内联函数通常只有几行代码。如:
inline int max(int a, int b){
if(a > b){
return a;
}
return b;
}
在调用上述
函数时如c = max(m, n);
,其大致流程为:
if(m >n){
temp = m; // 使用临时变量temp存储较大值
}else{
temp = n;
}
c = temp; // 将临时变量值赋值给结果
5. 函数重载
定义:在 中,一个或多个函数,名字相同、而参数个数或参数类型不同。而在 语言中不允许使用函数名相同的函数。例如下面为函数重载的三种形式:
函数重载使函数命名变得简单,编译器根据调用语句中实参个数或参数类型自动判断应该调的函数。调用实例:
Max(5, 6); // 调用上述第1个函数
Max(5.1, 6.1); // 调用上述第2个函数
Max(5, 6, 7); // 调用上述第3个函数
Max(5, 6.1); // 出错,出现二义性
注:不以两个函数的返回值类型判断是否为重载函数。
6. 函数的缺省参数
在
中,定义函数时可以让最右边的连续若干个参数有缺省值。在函数调用时,若相应位置不指定参数,则就会使用缺省值。如由函数定义为void fun(int a, int b=6, int c= 7){}
,则在以下函数调用的例子中:
func(5); // 等价于func(5, 6, 7);
func(5, 8); // 等价于func(5, 8, 7);
func(5, ,8); // 出错,只能最右边连续若干个参数有缺省值
函数的缺省参数的作用是可以使函数既可以执行默认的参数值,也可以执行用户指定的参数值。
参考
- 北京大学公开课:程序设计与算法(三)C++面向对象程序设计.