【c++primer】函数探幽

1.内联函数

正常调用函数的时候,指针跳到函数所在的位置,执行完之后返回到调用该函数的内存处。内联函数的编译代码与其他程序内联起来,执行的时候无需跳到另一个位置处,但是会牺牲内存。

如果代码执行时间短,则内联调用就可以省去非内联调用使用的大部分时间;如果函数经常被调用,也可以使用内联;内联函数不能递归。

使用:在函数声明前加上关键字inline或者在函数定义前加上inline。

c语言中的宏定义是内联函数的原型,比如#define SQUARE(X) X*X,但是只是将X替换,不能按值传递。


2.引用

(1)引用是指针的伪装表示,但是其只能在初始化时赋值,类似于const类型的指针。

int & a=b; 等同于 int * const c=&b;   

a和*c等同于b,&a和c等同于&b。a成为了b的别名。

(2)将引用作为函数参数,允许函数修改参数的值。

  • 在函数中使用const类型的引用可以提高效率,使用原来的参数,不需要复制参数,并且函数不会改变参数的值。
  • 仅当参数为const类型的引用时,如果实参与引用参数不匹配,c++将生成正确的临时变量。如果不是const类型,则实参与引用的参数类型不匹配时,将生成临时变量,引用修改的也只是临时变量,并没有修改原变量,所以此时的引用就会有警告。而const类型的引用本来就不改变原参数的值,因此这里的引用就是正确的。

如果引用是const类型,那么在以下两种情况下会生成临时变量:

实参类型正确,但不是左值;

实参类型不正确,但可以转换为正确的类型。

建议在不修改实参的情况下将引用参数声明为常量数据的引用,原因有以下几点:

const使函数能够处理const和非const的实参,否则将只能接受非const数据;

使用const引用能够使函数能够正确生成并使用临时变量。

(3)将引用用于结构

struct sysop{
        char name[26]; 
        char quote[64];
        int used;
};

const sysop & use(sysop & sysopref)
{
       sysop.used++;
       return sysopref;
}

void main()
{
        sysop looper={“sdfs”,"sdfsdf",4};
use(looper);
}

  • 将结构looper按引用传递给函数,使得sysopref成为looper的别名;
  • 使用引用作为函数的返回值,意味着调用程序将直接访问返回值,而不需要拷贝。(返回值不是引用的函数将返回值存储在一个临时的内存中,随后调用程序访问该临时内存)通常返回的是传递给该函数的引用,应避免返回当函数终止时不再在内存中存在的引用。
  • 返回类型为const的引用只是意味着不能使用返回的引用来直接修改它指向的结构。
(4)将引用用于类
string version(const string &s1,const string &s2)
{
       string tmp;
       tmp=s2+s1+s2;
       return tmp;}         //正确,s1和s2都不会被改变.也可以使用char*型的变量作为实参

const sting & version2(string &s1,const string &s2)
{
       s1=s2+s1+s2;
       return s1;
}    //有负面影响。这里s1就只能是string型的变量,char*的变量会出错。而s2就能够是char*型的变量。

const string & version3(string &s1,const string&s2)
{
      string tmp;
      tmp=s1+s2;
      return  tmp;
}    //错误的,变量tmp在函数调用结束之后就会释放,他的值会存在一个临时内存中,不能将他作为引用来返回
(5)对象、继承和引用
基类引用可以指向派生类对象,不用进行强制转换。

(6)小结
  • 何时使用引用参数:
修改调用函数中的数据对象;传递引用而不是整个数据对象。
  • 指导原则:
不需要修改值时:
数据很小时,值传递;
数据对象是数组时,使用const指针;
数据对象时较大的结构,使用const指针或者const引用;
数据对象时类对象时,使用const引用。
要修改值时:
数据对象为内置数据类型,则使用指针;
数据对象为数组,则使用指针;
数据对象为结构,使用指针或引用;
数据对象为类,则使用引用。

3.默认参数
将值付给函数原型中的参数。
从右向左添加默认值,即要为一个变量赋默认值,必须使得它右边的变量都赋有默认值。
int function(int m,int n=10,int j);   //错误
函数调用的时候从左向右将实参赋值给形参,不能跳过任何参数。
b=function(3,,5)  //错误

4.函数重载
参数类型和任何重载函数的形参类型都不同时,c++将尝试强制转换,但是如果有多种转换方式都满足,则报错;
编译器在检查特征标的时候,将引用和类型本身视为同一特征标;
函数返回类型可以不同,但特征标必须不同。

5.函数模板
template<class Any>       //这里写成template<typename Any>也可以,Any只是一个名称
void Swap(Any &a,Any &b)
{
      Any tmp;
      tmp=a;
      a=b;
      b=tmp;
}

template<typename Any>                  //这个在函数声明和函数定义的前面都要加上
void Swap(Any [],Any [],int)              //模板的重载应用。模板函数的形参并不一定都是模板参数
{
       Any tmp;
       for(int i=0;i<n;i++)
     {
           tmp=a[i];
           a[i]=b[i];
            b[i]=a[i];
       }
}
  • 对于给定的函数名,可以有非模板函数、模板函数和显示具体化模板函数以及它们的重载版本。
  • 显示具体化的原型和定义应以template<>打头,并通过名称来指出类型。(为什么不用非模板函数来替换显示具体化模板函数)
  • 编译器在选择原型时,非模板版本将优先于显示具体化和模板版本,显示具体化将优先于模板版本。
struct job;
void Swap(job &a,job &b);

template<typename Any>
void Swap(job &a,job &b);

template<>void Swap<job>(job &a, job &b);    //或者也可以写成template<>void Swap(job &a,job &b).






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值