C++ Primer Plus的若干收获--(五)

趁着最近有空多谢两篇博客。嘿嘿嘿,加油!嘿嘿嘿,加油!

 

5.1 将C-风格的字符串用作string对象的引用参数

先看一个函数

<span style="font-size:18px;">string version1(const string &s1,const string& s2)
{
  string temp;
  temp=s2+s1+s2;
  return temp;
}

//调用该函数
result=version2(input,'###');</span>

这里我们注意到“###”的类型为const char*。此时函数怎么能够接受char指针赋给string引用呢?这里有两点需要说明。首先,string类定义了一种char*到string的转换功能,这使得可以使用C-风格的字符串来初始化string对象。其次是之前讨论过的const引用的形参的一个属性。假设实参的类型与引用参数的类型不匹配,但可以被转化为引用类型,程序将创建一个正确的临时变量,使用转换后的实参值来初始化它,然后传递一个指向该临时变量的引用。例如在之前介绍的,将int实参传递给const double&形参时,就是以这种方法处理的。

 

5.2 对引用参数的一个小结

使用引用参数的原因有两个:

  • 程序员能够修改调用函数中的数据对象。
  • 通过传递引用参数而不是整个数据对象,可以提高程序的运行速度。

什么时候应使用引用,什么时候应使用指针,什么时候使用按值传递,下面给出一个指导原则:

  • 如果数据对象很小,如内置数组或小型结构,则按值传递。
  • 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为const的指针。
  • 如果数据对象是教大的结构,则使用const指针或者是const引用。用来提高程序的效率。这样可以节省复制结构所需的时间和空间。
  • 如果数据对象是类对象,则应该使用const引用。类设计的语义常常要求使用引用。因此传递类对象的参数的标准方式是引用传递。
  • 如果数据对象是内置的数组类型,则应该使用指针。
  • 如果数据对象是数组,则只能使用指针。
  • 如果数据对象是结构,则使用引用或是指针。
  • 如果数据对象是类对象,则应该使用引用。

 

5.3 函数的重载

函数重载就像是有多重含义的动词。例如PP小姐可以再棒球场为家乡的球队助威(root),也可以在天地里种植(root)作物。可以通过上下文来知道每一种情况下root的含义,同样C++也通过上下文来确定使用的重载函数版本。

函数重载的关键是函数的参数列表————也成为函数的特征标。如果两个函数的参数数目相同,且类型相同,参数的顺序也一样,则他们的特征标相同。但是有些看起来彼此不同的特征标是不能共存的,比如看下面:

<span style="font-size:18px;">double cube(double x);
double cube(double &x);</span>

如果并有下面的代码

<span style="font-size:18px;">cout<<cube(x);</span>

参数x与double &x的类型都汽配,因此编译器无法识别究竟应该使用哪个原形。为了避免这种混乱,编译器将在检查特征标时,将把类型引用和类型本身看做是同一个特征标。

另外在匹配函数时,并不区分const和非const变量。还有一种重载也是C++多不允许的

<span style="font-size:18px;">long gronk(int n,float m);
double gronk(int n,float m);</span>

返回的类型可以不同,但是特征标也必须相同。

 

5.4 函数模板函数模板是一个通用的函数描述,也就是说,他们使用泛型来定义函数,其中的泛型可以用于具体的类型。通过将类型作为函数传递给模板,可是编译器生成该类型的函数。这里给出一个交换模板

<span style="font-size:18px;">template<typename T>
void swap(T&a,T&b)
{
  T temp;
  temp=a;
  a=b;
  b=temp;
}</span>

在标准C++98添加关键字typename之前,其使用关键字class来创建

 

 

5.5 模板的具体化

实验其他的具体化方法后,C++98标准选择了下面的方法。

  • 对于给定的函数名,可以有非模板函数、模板函数与现实具体化模板函数以及它们的重载版本。
  • 显示具体化的原型和定义应以template<>打头,并通过名称来指定其类型。
  • 具体化优先于常规的模板,而非模板函数优先于具体化和常规模板。

下面给出用于交换job结构的非模板函数、模板函数和具体化的原型:

<span style="font-size:18px;">void swap(job&,job&);//non template function prototype

template<typename T>//template prototype
void swap(T&,T&);

template<>void swap(job&,job&);explicit specialization for the job</span>

 则在下面的调用过程中,第一次会使用通用版本,而第二次则会使用显式具体化版本

<pre class="cpp" name="code"><span style="font-size:18px;">int main()
{
  double u,v;
  ...
  swap(u,v);//use template
  job a,b;
  ...
  swap(a,b);//use void swap<job>(job&,job&)
}


</span>
 

 这里我再来介绍一下为什么会有需要显示具体化,这里我给出两个例子大家就会很容易理解

<span style="font-size:18px;">struct job
{
    char name[40];
    double salary;
    int floor;
};

template<typename T>
void swap(T&a,T&b)
{
    T temp;
    temp=a;
    a=b;
    b=temp;
}

template<>void swap<job>(job&j1,job&j2)
{
    double t1;
    int t2;
    t1=j1.salary;
    j1.salary=j2.salary;
    j2.salary=t1;
    t2=j1.floor;
    j1.floor=j2.floor;
    j2.floor=t2;
}</span>

虽然都是交换,但是二者显然有着明显的区别。

 

5.6 再论模板的实例化与具体化

为了进一步了解模板,必须理解术语实例化和具体化。在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,得到的是模板实例。模板并非函数定义,但是使用int的例是函数定义,这种实例化的方式被称为隐式实例化。最初,编译器只能通过隐式实例化,来使用模板生成函数定义,但是现在C++还允许现式实例化。如前面的例子,它需要<>来指示类型,并加上关键字template。

隐式实例化、现实实例化和现实具体化均成为具体化。它们的相同之处在于,它们表示的都是具体类型的函数定义,而不是通用描述。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值