1.内联函数:是以空间(内存空间)代价换取时间的(程序执行效率),不能使用递归。既可以用于值传递,也可以用于地址传递,而宏不能用于
值传递。内联函数一般在如下情况下采用:程序中多次调用,而且函数代码执行时间较短时采用。
2.引用(变量):主要用途是用作函数的形参。
3.引用与指针的区别:
(1)引用必须在其声明时就初始化,即必须在创建时就将它初始化,而不像指针那样,可以先声明,后初始化
#include<iostream>
using namespace std;
int main()
{
int rat = 100;
int & shu = rat;
cout << "rat = " << rat;
cout << ", " << "shu = " << shu << endl;
cout << "rat address: " << &rat ;
cout <<", " << "shu address: " << &shu <<endl;
int cat = 50;
shu = cat;
cout << "cat = " << cat;
cout <<", " << "rat = " << cat ;
cout <<", " << "shu = " << shu <<endl;
cout <<"cat address: " << &cat;
cout <<", " << "shu address: " << &shu <<endl;
cin.get();
return 0;
}
运行上面程序结果如下:
上面结果,显示了,rat的值也变成了50,同时,rat与shu地址相同,而该地址与cat地址不同。因为shu是rat的别名,所以shu=cat语句的与下面语 句等效:rat = cat;也意味着将cat变量的值赋给rat变量。通过上面例子,总之,可以通过初始化声明来设置引用,而但不能通过赋值来设置引用,否则
会出现意想不到的严重的后果。
4.引用的一个作用就是用作形参,但注意:用引用做参数时(形参),它很有可能习惯调用函数的值,即实参的值。
临时变量、引用参数和const:
如果实参与引用参数不匹配,则C++将生成临时变量,现在,仅当参数为const引用时,C++才允许这样做的。
如果引用参数为const,则在以下两种情况会产生临时变量:
a.实参的类型不正确,但不是左值。
b.实参的类型不正确,但可以转换为正确的类型。
左值参数是可被引用的对象,例如,变量,数组元素,结构成员,引用或被解除引用的指针都是左值。
非左值包括字面常量和包含多项的表达式。
示例:
double refcube(const double & ra)
{
return a*a*a;
}
double side =3.0;
double *pd = &side;
double & rd=side;
long edge = 5L;
double lens[4] = {1.0,2.0,3.0,4.0};
double c1= refcube(side) ; //ra is side;
double c2=refcube(lens[2]); //ra is lens[2]
double c3= refcube(rd); //ra is rd is side
double c4 = refcube(*pd); //ra is *pd is side
double c5 = refcube(edge); //ra is temporary variable
double c6 =refcube(7.0); //ra is temporary variable
double c7 = refcube(side + 10.0); // ra is tempoary variable
参数side、lens[2]、rd和*pd 都是有名称的、double数据类型的对象,因此可以为其创建引用,而不需要临时变量。但是,edge虽然是变量,类型
却不正确,double引用不能指向long,还有,参数7.0和side+10.0虽然类型正确,但没有名称,在这种情况下,编译器将生成一个临时匿名变量,
并让ra指向它。这些临时变量只在函数调用期间存在,此后编译器便可以随便将其删除。
在没有特殊情况下,一般讲形参引用设为const,应尽可能使用cosnt,原因有如下三点:
(1)使用const可以避免无意中修改数据的编程错误。
(2)使用const使函数能够处理const和非const实参,否则将只能接受非const数据
(3)使用cosnt引用使函数能够正确生成并使用临时变量
5.引用的第二个作用:用于结构。
#include<iostream>
using namespace std;
struct sysop
{
char name[26];
char quote[64];
int used;
};
const sysop & use(sysop & sysopref)
{
cout << sysopref.name <<"says: " << endl;
cout << sysopref.quote <<endl;
sysopref.used ++;
return sysopref;
}
int main()
{
sysop looper =
{
"caizhiming",
"宝剑锋从磨砺出,梅花香自苦寒来",
0
};
use(looper);
cout <<"Looper: "<<czm.used << " use(s)" <<endl;
sysop copycat;
copycat = use(looper);
cout <<"Looper: "<<looper.used << " use(s)" <<endl;
cout <<"Copycat: "<<copycat.used << " use(s)" <<endl;
cout <<"use(looper): "<<use(looper).used << " use(s)" <<endl;
cin.get();
return 0;
}
在上面程序代码中,将引用作为返回值。通常,返回机制将返回值复制到临时存储区域中,随后调用程序将访问该区域,然后,返回引用意味着调用程序将直接访问返回值,而不需要拷贝。通常,引用将指向传递函数的引用,因此调用函数实际上是直接访问自己的一个变量。例如上面例子中,sysopref是looper的引用,因此返回值是main函数中的原始looper变量。
返回引用时应注意:避免返回当函数终止时不再存在的内存单元引用,同样使用指针时也应避免返回指向临时变量的指针!
6.引用的第三个个作用:用于类对象
将类对象传递给函数时,C++通常的做法就是使用引用。例如,可以通过引用,让函数将类string、ostream、istream、ofstream和ifstream等类的对象作为参数。如果一个类是从另一个类派生出来的,则基类的引用可以指向派生类的对象。
7.对于什么时候使用引用,什么时候使用指针,什么时候应按值传递,一般遵循以下原则:
(1)对于使用传递的值而不作修改的函数:
a.如果数据对象很小,如内置数据类型或小型结构,则按值传递。
b.如果数据对象是数组,则使用指针,因为这是唯一的选择,并且将指针声明为指向const的指针。
c.如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构的空间和时间。
d.如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,这是C++新增引用的主要原因,因此,传递类对象参数的标准方式是
按引用传递。
(2)对于修改调用函数中数据的函数:
a.如果数据对象是内置数据类型,则使用指针。如果看到fixit(&x)这样的代码(其中x是int类型),改函数将修改x。
b.如果数据对象是数组,则使用指针。
c.如果数据对象是结构,则使用引用或指针。
d.如果数据对象是类对象,则使用引用。
引用的引入只要适用于结构和类对象的。
8.函数重载:函数重载的关键是参数列表——也称为函数特征标。函数重载必须是特征标不同,返回类型可以不相同。函数名相同,只需要特征标(参数列表)不同,就是函数多态(或函数重载)。函数模板自动完成重载函数的过程。
9.函数模板:这里要注意的是 template<class T> 不是一个独立的语句,它必须和方法定义声明或类声明是一体的,虽然有时分两行来写。
代码示例:
#include<iostream>
using namespace std;
template<class T>
void Swap(T &a,T &b);
template <class T>
void Swap(T &a,T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int i=10;
int j=20;
cout << i << "," << j <<endl;
Swap(i,j);
cout << i << "," << j <<endl;
double m = 12.34;
double n =20.57;
cout << m << "," << n <<endl;
Swap(m,n);
cout << m << "," << n <<endl;
cin.get();
return 0;
}
10.默认参数:
如果第N个参数默认的话,第N+1 N+2 …… 个都应该是默认参数,所以默认参数应该放在参数列表的最“后”面。也即是说,如果要为某个参数设置为默认值,则必须为后面的所有参数提供默认值。