C++学习随笔之五:C++函数的新特点

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;

}

运行上面程序结果如下:

 C++学习随笔之五:C++函数的新特点_第1张图片

上面结果,显示了,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 …… 个都应该是默认参数,所以默认参数应该放在参数列表的最“后”面。也即是说,如果要为某个参数设置为默认值,则必须为后面的所有参数提供默认值。

你可能感兴趣的:(C++)